I want to learn the comment displaying algorithm behind Reddit. How is a comment related with its child and so on? How they are stored in the database?
Lets say
comment1
-comment2
--comment3
-comment4
--comment5
--comment6
---comment7
----comment8
comment9
How to display comment5 which is after comment4 which is after comment1? What is the idea behind this sequencing? And how to relate them in the database?
It is called hierarchy. Each comment either has no parent comment, or has one parent comment. This way you can display every "top level" comment (thanks to the fact they have no parent comments), then child comments for each of them etc. etc.
And the database structure may look like this for comments table:
id field identifying single comment,
parent_id being set to parent's ID or not set (set to NULL or set to 0),
created - timestamp for comment creation,
content - actual comment content,
any additional field you need,
AS #Rafe said, the actual storage is pretty easy, it would be something like:
| id | name | parent |
| 1 | comment1 | 0 |
| 2 | comment2 | 1 |
| 3 | comment3 | 2 |
| 4 | comment4 | 1 |
| 5 | comment5 | 4 |
| 6 | comment6 | 4 |
| 7 | comment7 | 6 |
| 8 | comment8 | 7 |
| 9 | comment9 | 0 |
Of course actually getting information from this is (arguably) the hard part. You can of course get the children of a comment with something like: SELECT * FROM table WHERE parent='4' will give you all the children of comment4. But counting children, listing all the children in hierarchical order would be a bit harder. Other answers may provide more information on that.
Pretty much what #Rafe Kettler noted - comments can have parent columns. However, if you want a more detailed and in-depth algorithm to use as a pattern for your implementation, take a look at this message threading algorithm.
Related
Suppose I have a experts table like this :
+-----------+----------+----------+--------+
| expert_id | name | family | active |
+-----------+----------+----------+--------+
| 1 | ali | ahadi | 1 |
| 2 | reza | hosseini | 1 |
| 3 | hossein | rezaei | 0 |
| 4 | mohammad | gholami | 1 |
+-----------+----------+----------+--------+
And in the other hand there is a questions table like this :
+-------------+-------+-----------+
| question_id | title | expert_id |
+-------------+-------+-----------+
| 1 | A | 1 |
| 2 | B | 2 |
| 3 | C | 4 |
| 4 | D | 1 |
| 5 | E | 2 |
| 6 | F | 4 |
+-------------+-------+-----------+
I'm working on a Question-Answer App. when a user asks a new Question I want to select an expert(of course activated expert, means an expert that has active field equal to 1) that can answer to question .(expert_id field holds the selected Expert ID in the questions table).
But I do not want this to be a random selection. Instead, I want to be sequentially as you can see in the expert_id of questions table.
In fact ,since that daily many questions may be asked I would like divide questions between the experts equally.
I want to do it in laravel But I do not know how I could implement this logic.
Can anyone help me to do that or suggest better ways?
I would suggest you keep a running total of the number of questions each expert has, that way you can assign it to the person with the lowest number of questions. You could even make this the total number of unanswered questions each expert has, which gets lowered when an expert answers the question so those experts that answer questions more frequently get more questions and those with less time to answer questions, or difficult questions that take a long time to answer, get less questions.
The way to do this would be to add another field onto the experts table, num_questions. When selecting experts you could do something like $expert = Expert::where('active', '=', 1)->orderBy('num_questions')->first(); then just assign the question to that user and increment the num_questions field by one for that user. You'd then just need to decrement that number when the user answers a question (if you want unanswered questions over total questions).
I have task that would be quite simple using regular SQL query but the project is built using doctrine and I am looking for an optimal solution. Maybe someone could advise what would be a good way to approach this.
I have a quite complicated db structure but the simplified version of objects in question look like this:
| Category | | Product | | ProductOption |
------------ --------------- --------------------
| id | | id | | id |
| name | | category_id | | product_id |
------------ | name | | some_data |
--------------- --------------------
Product Option and Product have 1 to 1 connection. But options are created per category (I get 1 entity per category, but need to replicate that entity for every product and store that as 1 to 1 since at some point those options will need to be edited individually. Now there are many ways to do that (the dirty way) , but I would like some advice on how to do that in the most optimal way.
I am a beginner developer and i would like to ask some advice.
I am currently building a platform where people will be allowed to upload images and tag them.
I was reading through some articles with the following structure to store tags
Storing Logic 1
| photo_id | name | tags |
| 1 | some photo | flower, sun. island, beach |
| 2 | some photo2 | hawaii, travle. surf |
Lot of people said this is not such a good idea
So my logic.
I was reading around about Many-to-Many relations and i came up with this logic
Tags table
| tag_id | name |
-----------------------
| 1 | flower |
| 2 | hawaii |
| 3 | surfing |
| 4 | island |
| 5 | travel |
Photos table
| photo_id | name |
---------------------------
| 1 | some photo |
| 2 | some photo2 |
Relation table
| tag_id | photo_id |
---------------------------
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
I have chosen to use Laravel framework to make the development easier
But my problem is with logic 2 and what i am scared of is it will generate a huge load time.
Because there will be no default just user based tags i thought about the following logic.
User uploads the image with tags, before image is saved, check if the actual tags exsit if not save it, than return tags_id and save it to the relation table with photo_id
So i have 2 questions
Which logic is better and why?
If logic 2, is it good the way i thought it up? and should i worry about the load time in the future when lot of tags will be there?
thank you
I would go with the second one. I wouldn't worry about load times. You can easily get the categories with joins.
However, you should add an id column on the relation table so that multiple images can share a category.
In your second example, your relation table should have indexes, so that when you look for all the tags based on a specific photo_id, the answer will be rapidly returned.
See also Foreign Keys
In your relation table, tag_id is a foreign key into your tag table and photo_id is a foreign key into the photo table. Tags may have a relationship to more than 1 photo and a photo may have a relationship to more than one tag.
Similarly the names of your tags (and photos) should also be indexed for rapid searching.
I don't know if what I'm asking is even possible, but here's my situation. I have a table structured somewhat like this:
+--------------------------------------------------+
| id | parent_id | name | category | ....
+--------------------------------------------------+
| 0 | -1 | item0 | 1 |
| 1 | 0 | item1 | 1 |
| 2 | 0 | item2 | 1 |
| 3 | 2 | item3 | 1 |
| 4 | 2 | item4 | 1 |
| 5 | -1 | item5 | 1 |
+--------------------------------------------------+
A parent_id of -1 will mean it is a "base" item with no parent. Each item will have more columns of information. I need to somehow output all items in a category nested like the following:
item0 => item1
=> item2
=> item3
=> item4
item5
I don't know if that makes sense or not, but hopefully it does!
The only way I can think of doing this is making a query to get all of the "base" items (querying for rows with parent_id = -1) then iterate through every resulting row, querying for rows that have their parent_id equal to the current row's id, then repeating the process going deeper and deeper until there aren't any more children for a base item.
Is there a better way?
Thanks!!
It is not possible in pure SQL.
SQL is intended to work with relational data not trees (hierarchical data).
You can represent tree in an SQL schema, however you won't be a able to result in a tree as you intend to do.
The only way to do is to get an usable result by making as many join as level you're storing.
Your current schema may support multiple level, however, it will be very difficult to manage more than one or two level.
You may be interested in Nested Set Model or Managing hierarchical data in mysql
There are some implementation of the Nested Set like this one to work with Doctrine 2
This is not possible in pure SQL and it is one of the aspects of the relational model that generates most criticism.
I would recommend you to read the links on this post: SQL "tree-like" query - most parent group
And also, if your application relies too much on this, I would suggest you to take a look at some non-relational databases that can represent this kind of data way better, such as MongoDB ( www.mongodb.org )
I hope i understood well your question(it's pretty late here and i've just come from a bar), if i didnt, just correct me and i'll rewrite my answer.
From the scenario given, i guess there's another parent table, isn't there?
Lets imagine it's attributes are id and name. Children table is the given one by you (w/o unnecessary attributes).
mysql> insert into parent(name) values ('petr'),('tomas'),('richard');
mysql> insert into children(name,parent_id) values('michal',1),('tomas',1),('michal');
mysql> select parent.id,parent.name,children.name from parent left join children on parent.id = children.parent_id;
+----+---------+--------+
| id | name | name |
+----+---------+--------+
| 1 | petr | michal |
| 1 | petr | tomas |
| 2 | tomas | NULL |
| 3 | richard | michal |
+----+---------+--------+
In order to do this multiple time (parent got child who got child who got child etc..) You can accomplish that by using multiple joins.
mysql> select parent.id,parent.name as Parent,children.name as Child,children2.name as Child2 from parent left join children on parent.id = children.parent_id left join children2 on children.id = children2.parent_id;
+----+---------+--------+--------+
| id | Parent | Child | Child2 |
+----+---------+--------+--------+
| 1 | petr | michal | NULL |
| 1 | petr | tomas | dan |
| 1 | petr | tomas | pavel |
| 2 | tomas | NULL | NULL |
| 3 | richard | michal | michal |
+----+---------+--------+--------+
If i either didnt answer what you asked or you need further explanation let me know ;]
Regards,
Releis
I want to create something like reddit where they have comments, then replies to the comment, then reply to the reply.
What type of database structure do they use so:
1. they keep track of all the comments to a posting
2. a reply to a comment
3. a reply to a reply
All I have right are is just a posting and a bunch of comments relating to it like..
POSTING TABLE
posting_id | title | author
COMMENTS TABLE
comment_id | posting_id | comment
REPLIES TABLE
????
How do I relate the comments to the replies?
What type of css do they use to give replies that indented space?
EDIT:
Thanks for the answers! Now my only question how do I indent the replies?
Such as..
you like food
yes I love italian
Yes i do like it too
chinese is best
You can add another column to your comments table specifying parent_comment_id where you populate it with the ID of the comment (or reply) the user is replying to. In the case where the comment is a direct reply to the post (not a reply to a comment) this column would be null.
To show replies inside replies, you'll have to do a recursive call to keep on generating the sub replies.
Something like
function get_comments($comment_id) {
print '<div class="comment_body">';
// print comment body or something?
if (comment_has_reply($comment_id)) {
foreach(comment_comments($comment_id) as $comment) {
get_comments($comment->id);
}
}
print '</div>';
}
To indent comments however, use css.
<style type="text/css">
.comment_body {
margin-left:10px;
}
</style>
This way sub replies are indented more than the parent, and their subs are indented even more, and so on.
I would do that by making a cross reference table.
Example:
Table: Posts
Columns: pstkey | userid | postMessage | etc...
pstkey is the key for the post body. userid is the person who created the post. postMessage is the actual post entry.
Table: Comments
Columns: comkey | pstkey | userid | commentMessage | etc...
comkey is the key for the comment made. referenced to the post using the pstkey. userid is the person who made the comment. and then commentMessage is the text body of the actual comment.
Table: xref_postComm
Columns: xrefkey | pstkey | comkey | comkey2 |
Now for the fun part. ALL posts go into post table. ALL comments go into comment table. The relationships are all defined in the Cross Reference Table.
I do all of my programming this way. I was privileged to work with one of the worlds bests database engineers who was retired and he taught me a few tricks.
How to use the Cross Reference table:
xrefkey | pstkey | comkey | comkey2
All that you look for is the population of a given field.
xref (Auto Incremented)
pstkey (Contains the pstkey for the post)
comkey (Contains the comkey for the comment post)
comkey2 (Contains the comkey for the comment post)
(but only populate comkey2 if comkey already has a value)
and of course you populate comkey2 with the key of the comment.
SEE, no reason for a 3rd tabel!
With this method you can add as many relationships as you want.
Now or in the future!
comkey2 is your reply to a reply. Where which this single row contains.... the key of the post, the key of the comment, and the key of the reply to the reply comment. All done by population of xref.
EXAMPLE:
PAGES.... Page table
POSTS
pstkey | pageid | user| Post
-------------------------------------
| 1 | 1 | 45 | Went to the store the....|
| 2 | 2 | 18 | Saw an apple on tv.....
COMMENTS
comkey | pstkey | user | Comment
-----------------------------------------------
| 1 | 1 | 9 | Wanted to say thanks...
| 2 | 1 | 7 | Cool I like tha.....
| 3 | 2 | 3 | Great seeing ya....
| 4 | 2 | 6 | Had a great....
| 5 | 2 | 2 | Don't sweat it man...
xref_PostCom
xrefkey | pageid | pstkey | comkey | comkey2 |
----------------------------------------------
| 1 | 1 | 1 | NULL | NULL | Post1 on Page1
| 2 | 1 | 1 | 1 | NULL | Comment1 under Post1
| 3 | 1 | 1 | 2 | NULL | Comment2 under Post1
| 4 | 2 | 2 | NULL | NULL | Post2 on Page2
| 5 | 2 | 2 | 3 | NULL | Comment3 under Post2 on Page2
| 6 | 2 | 2 | 4 | NULL | Comment4 under Post2 on Page2 (a second Comment)
| 7 | 2 | 2 | 4 | 5 | Explained below....
Comment key 5 is matched with comment key 4....under post2 on Page 2
If you know anything about join, left join, right join, inner/outer join creating SELECT's to get the data arrays using these relationships, your job becomes a whole lot easier.
I believe the engineer's call this basically "the data map" of defined relationships. The trick is now how you access them using these relationships. It seams hard at first, but know what I know it, I refuse to do it any other way.
What happens in the end is you end up writing 1 script that says, ok, go do uhh, everything and come back. You will end up with 1 function call that asks for page 1. It returns with page1, post 1, comment1&2&3 and the replies to the reply in 1 array. echo to output and done.
UPDATE FOR COMMENT
I said the same exact thing the first time it was shown to me. As a matter of fact it really was making me mad that the database programmer was forcing me to do it this way. But now I get it. The advantages are so many.
Advantage 1) 1 query can be written to pull it all out in 1 shot.
2) Answers in multiple queries can populate arrays in a structure that when printing the page a loop in a loop can display the page.
3) Upgrading your software that uses it can support any possible design change you can ever think of. Flawless expandability.
The guy who taught it to me was the hired gun who redesigned sears and jcpenny databases. Back when they has 9 books going to the same house because of duplicate records issues.
Cross reference tables prevent a lot of issues in design.
The heart to this theory is, a column can not only contain data but serve as a true or false statement at the same time. That in it's self saves space. Why search 20 tables when you can search one? 1 indexed cross reference table can tell you everything you need to know about the other 20 tables, it contents, what you need, what you don't need, and do you even need to open the other table at all.
IN SHORT:
1 Cross reference containing nothing but INT(2/11) that tells you everything thing you need to know before you ever open another table, not only contains flawless expandability but lighting speed results. Not to mention little possibility of duplicate records. To you and me duplicate records may not be an issue. But to Sears with 4 billion records at $11 a book, mistakes add up.
Add another field to your comments table which "reply_to" or some such, and store the id of the comment which it is in reply to there.
you could make the comments table generic like so :
COMMENTS TABLE
comment_id | posting_type | posting_id | comment
where posting_type is some sort of discriminator, eg a string 'POST' or 'COMMENT', or an integer for more efficiency (1 = POST, 2 = COMMENT, etc).
edit : admittedly this is more complicated but it means you can use the same comment table for comments on anything, not just posts and other comments.
You don't need the replies table. As others already correctly have pointed out, recursion is the way to go with an RDBMS. You could always consider using a nosql style DBMS, to avoid having to deal with recursion.