I have a site which allows users to make changes to content. How can I implement a rollback system? I'm using php and mysql, I was thinking of creating tables such as the following:
posts table --- posts_rollback table --- rollback table
The posts_rollback table would act as a lookup table. The posts table has a one to many relationship with the posts_rollback table. I would then use inner_join to
Is there a better way of doing this or any class/feature which automatically does this itself?
I think what you mean is content versioning (like here on SO) rather than rollbacks - the term "rollback" is mostly used in context of database transactions.
The simplest thing that comes to mind is to have two tables: posts that stores non-editable data (author, date created) and content with versioned data (text, date-updated, editor etc). Have a field called "version" in the posts table. When a post is updated, increase "version" and insert the data into content, along with post ID and "version". When retrieving posts, join content with posts on posts.id and posts.version.
Related
We have a php/mysql system with about 5 core entities. We now need to add the ability for customers to create custom fields for some of these entities on a per project basis.
They would contain a label, key, type, default value, and possible allowed values.
This is so they could add a custom date field, or a custom dropdown to the UI and save this value against the specific entity.
What is the best approach for storing this kind of data in a mySQL database? I need to store both the config for the field, and then the current value for a specific entity.
I've had a look at various options here.. https://ayende.com/blog/3498/multi-tenancy-extensible-data-model
But this is not really at a tenancy level, more a project level.
I was thinking...
A CustomFields table to hold the configuration of a field against an entity type and project id.
A CustomFieldValues table to hold the value saved against the field - a row per field ( entity_id | field_id | field_value)
Then we create relationships between the entities and these custom values when retrieving the entities.
The issue with this is that there will be as many rows in the Values table as there are custom fields - so saving a entity will result in X extra rows. On top of that, these are versioned, so once a new version is created, there will be another X rows created for that new version.
Also, you can't index the fields on name, joins would become pretty complex i think as you have to join to the configuration and the values to build the key value pair to return against the entity, and how would you select based on a custom field name, when the filed name was actually a value?
I don't want to add dynamic columns to the table, as this will affect ALL the entites in the whole system - not just the ones in the current client / project.
The other option is to store the values in a JSON column.
This could be on the entity row itself customFields or similar. This would prevent the extra rows per field, but also has issues with lack of indexing etc, and still need to join to the config table. However, you could perform queries by the property name if the key=value was stored in the JSON... WHERE entity.customFields->"$.myCustomFieldName" > 1.
Storing the filed name in the json does mean you cannot change it once created, without a lot of pain.
If anyone has any advice on approaches for this, or articles to point me at that would be much appreciated - Im sure this has been solved many times before....
JSON records: No! A thousand times no! If you do that, just wait until somebody actually uses your system for a few tens of millions of records, then asks you to search on one of your extra fields. Your support people will curse your name.
Key-value store. Probably yes. There's a very widely deployed existence proof of this design: WordPress. It has a table called wp_postmeta, containing metadata fields applying to wp_posts (blog pages and posts). It's proven successful.
You will need to do some multiple joining to use this stuff. For example, to search on height and eye-color, you'd need
SELECT p.person_id, p.first, p.last, h.value height, e.value eye_color
FROM person p
LEFT JOIN attrib h ON p.person_id = h.person_id AND h.key='eye_color'
LEFT JOIN attrib e ON p.person_id = e.person_id AND e.key='height'
WHERE e.value='green' and CAST(h.value AS INT) < 160
As the CAST in that WHERE clause shows, you'll have some struggles with data type as well.
You'll need LEFT JOIN operations in this sort of attribute lookup; ordinary inner JOIN operations will suppress rows with missing attributes, and that might not work for you.
But, if you do a good job with indexes, you'll be able to get decent performance from this approach.
The table structure envisioned in my example doesn't have your table describing each additional field, but you know how to add that. It also doesn't have explicit support for multi-project / multitenant data separation. But you can add that as well.
I'm designing a blog database. I want posts to belong to any number of categories, including none (i.e. number of categories = 0, 1, 2, 3, ...).
I understand that the common way to design such a database (e.g. in Wordpress), is to have one table for posts, one table for categories, and one table for relationships, thus:
table relationships
column relationship id
column post id
column category id
But this means that to display a post, my script will have to make at least three database queries. This seems slow to me.
Which is why, in another blog, I had only one table for posts which included a varchar column for categories, in which I inserted a string with all the category names, which I parsed in PHP, thus
table posts
column post id
... (many other columns)
column categories
where column categories contained a string that might look like this:
apples,oranges,bananas
which I simply explode()ed in PHP.
Please explain why I should avoid the second method (one table, explode). There must be something wrong with it that I miss, because it is not commonly used in blog software.
Note:
There might still be a table listing categories, into which new categories are written when a post is created, and from which lists of categories are drawn to display them in, of example, the sidebar.
I expect there to be many more queries for posts than for posts-in-categories, which is why I don't worry much about querying the second database for posts from a certain category, which might be faster in the first database.
In second case you will get huge problems with finding post by some category.
For example, you write posts about programming languages and want to show all post about python, php, ruby, etc on separate pages ... but you can't write simple and quick request to database because you violates 1 normal form in your second database scheme.
JimL has already mentioned JOIN which allows to make 1 request and get all needed information from standard many-to-many relationship scheme with link table post2category
I want to create a posting system to a profile. I created a database for storing all users posts each user have a table.
Ihad created another database for storing the comments of each posts. My logic is to create each table in the comments database and store each comment in that.
Is there a logic to link the post and the comments. I thought to use mysql last insert id but it will return last id which will create error because one of the post will not have a table.
Is there any other way?
Another way would be to have a single table for posts, and identify a user post in the table using a userid column. To find all posts by a particular user, simply query by the user's ID. By doing so, you have a single table to manage, and you can do a lookup easily. If you create separate tables for each user, you have to create additional logic to first figure out which table to use. If a user is removed, you delete a table, rather than simply removing some rows from a common table.
The same logic applies to the comments table - add columns for postid',commentid,userid`. Again, a single table contains all the comments. To find comments on a particular post, you would do a simple query such as
select comment_text
from comments_table
where postid = ?
The whole purpose of using MySQL is to leverage relationships between entities, i.e. a user owns posts, a post is linked to comments.
If you do not want to use a relational schema like this, take a look at NoSQL DBs.
You have a couple options here:
Add a user_id column to your posts table, and a post_id, and user_id column to your comments table. You can then setup foreign keys with one-to-many relationships.
Only use a single table that has (in addition to your existing) a user_id, and type column. Type will define comment/post/etc. This can be defined with intermediary tables as a number mapped to a CONST, string, or any other way that you see fit (intermediary best option imho).
Vary the above example and use 2 intermediary tables to match users to posts and comments to posts (possibly also users to comments).
I have set up a company intranet website built with PHP/MySQL and allow users to post reviews. After joining up on this website I have grown to like the "comment" function and would like to add that same functionality to allow users to "comment" directly to other users reviews.
Currently all reviews are stored in a single table in the DB.
1) Should I create another table to then store all the comments since there can be many comments per review?
2) Once I figure out where to store these values can the rest of this functionality be built out in PHP or will other programming need to also be introduced?
Sounds like a good plan. You can have a table like Comments(commentID, reviewID, comment_body, ...). You can then insert a new entry when adding a new comment, or select all comments with a given reviewID to display comments for a given review.
Yes, you will almost certainly implement this in PHP (the same language you use in the rest of your application). You'll also have to edit some HTML, and maybe javascript as well.
Yes and yes.
Comments should be a seperate table, because they're comments, not reviews. They are two different things, therefore, they should not go in the same table.
Once you've created that table with the appropriate references to other tables, it's just a matter of constructing a query which pulls out all of the information you need (e.g. SELECT user.user_name, comment.comment_text, comment.post_time FROM comment, user WHERE comment.user_id=user.user_id AND comment.review_id = 123, where 123 is the ID of the review you're getting comments for).
The exact layout for your comment table will depend on your specific needs, but as a minimum, you'll want to know which review it's a comment for, who posted it, when they posted it, and what they actually posted.
To insert comments, create a form on the page that displays the individual review, and when filled in, create an INSERT query which inserts into your comment table.
I'm building a website that constructs both site-wide and user-specific activity feeds. I hope that you can see the structure below and share you insight as to whether my solution is doing the job. This is complicated by the fact that I have multiple types of users that right now are not stored in one master table. This is because the types of users are quite different and constructing multiple different tables for user meta-data would I think be too much trouble. In addition, there are multiple types of content that can be acted upon, and multiple types of activity (following, submitting, commenting, etc.).
Constructing a site-wide activity feed is simple because everything is logged to the main feed table and I just build out a list. I have a master feed table in MySQL that simple logs:
type of activity;
type of target entity;
id of target entity;
type of source entity (i.e., user or organization);
id of source entity.
(This is just a big reference table that points the script generating the feed to the appropriate table(s) for each feed entry).
In generating the user-specific feed, I'm trying to figure out some way to join the relationship table with the feed table, and using that to parse results. I have a relationships table, comprised of 'following' relationships, that is similar to the feed table. It is simpler though b/c only one type of user is allowed to follow other content types/users.
user/source id;
type of target entity;
id of target entity.
Columns 2 & 3 in the feed and follow table are the same, and I have been trying to use various JOIN methodologies to match them up, and then limit them by any relationships in the follow table that the user has. This is has not been very successful.
The basic query I am using is:
SELECT *
FROM (`feed` as fe) LEFT OUTER JOIN `follow` as fo
ON `fe`.`feed_target_type` = `fo`.`follow_e_type`
AND fo.follow_e_id = fe.feed_target_id
WHERE `fo`.`follow_u_id` = 1 OR fe.feed_e_id = 1
AND fe.feed_e_type = 'user'
ORDER BY `fe`.`feed_timestamp` desc LIMIT 10
This query also attempts to grab any content that the user has created (which data is logged in the feed table) that the user is, in effect, following by default.
This query seems to work, but it took me sometime to get to it and am pretty sure I'm missing a more elegant solution. Any ideas?
The first site I made with an activity feed had a notifications table where activities were logged, and then friends actions were pulled from that. However a few months down the line this hit millions of records.
The solution I am programming now pulls latest "friends" activities from separate tables and then orders by date. The query is at home, can post the example later if interested?