Embeded comment paging in mongodb - mongodb

if I got a collection for storing Articles with it's Comments embedded, when retriving data from db, I will get a Article object with a completely Comment list, support there are a lot of comments, so this could be a problem of loading efficience, how can I handler this by paging Comments? do I have to use a seperate collection for Comments? or what else? thanx in advance.

You looking for the $slice operator.
To retrieve comments by paging you need code like this:
db.articles.find({}, {comments:{$slice: [20, 10]}}) // skip 20, limit 10
This operation will return articles with only sliced comments. )

The biggest question is:
Are your users more interested in comments or in context viewed?
Highly:
Put comments in separate documents, and load them first!
Then send "secondary" content via AJAX.
Moderately:
Use Andrew's solution. (And do not forget that you can also omit fields in queries)
Hardly:
Put comments in separate documents, and load them last (via AJAX).
(Also using AJAX can give you nice feature of expanding loaded comments via simple scrolling down)

Related

Sails.js one to many embedded associations with mongo

On the sails documentation here it shows modeling one to many associations with what looks like high level referencing.
Lets say I want to use mongo to make a post that has a lot of comments on it. I will take the post as the document and in it I will embed all the comments in one attribute.
If I did it like the documentation, would the mongo adapter automatically, create a document with the comments embedded? or would it do something relational and reference the comments?
If it doesn't embed, how would I go about putting the embedded comments in my model?
Thanks
Mongo doesn't provide associations on its own. Sails uses Waterline for ORM.
You need to create your Comment object yourself and just add its id to the appropriate attribute in the Post instance(which should be a collection), using post.comments.add(comment.id).
Removal is similar, just call post.comments.remove(comment.id)
Note that at some point you might not like to have thousands of commentids being fetched every time you retrieve a Post (or worse, thousands of Comment documents if you populate and fetch). This, of course, is only a concern if you're expecting thousands of comments per post in the first place.
Oh, and don't forget to save your document to finalize the changes.

how to populate a schema not referenced inside it

I have a blog and a comment schema. In the comment schema the blog Id is being referenced. Now I have a function that lists all the blogs when the index page loads and it gets it by doing Blog.findById(id).populate('user','username'). I want to also be able to populate all the comments this blog has but comments are not referenced inside the blog schema. I know that in the exec callback I can then do comment.find(blogid) but that is just tedious. I want to know if there is a better way of doing this. Thanks
If you are not referencing the comments in the blog schema, there is no way you can populate it. populate is only used for fields present in the document. As you said, getting all the comments with the blog _id using comment.find in the callback of Blog.findById for the schema you are using is the way to go.
To make this process more efficient keep an index (documentation) on the blogid field in the Comment collection. This will back the comment.find({blogid:<some blogid>}) more efficient as indexed queries are super fast.

Best way to store/get values referenced from a list in Mongo/RectiveMongo?

I have a quite common use case - a list of comments. Each comment has an author.
I'm storing the reference from a comment to the author using a reference, since an author can make multiple comments.
Now I'm working with ReactiveMongo and want to try to keep the database access asynchronous, but in this case, I don't know how. I do an asynchronous access to the database, to get the comments, but then for each comment I have to get the author, and until now the only way I know is to loop through the comments and get the user synchronously:
val userOption:Option[JsObject] = Await.result(usersCollection.find(Json.obj("id" -> userId).one[JsObject], timeout)
//...
Other than that, I could:
Get each user asynchronously but then I have to introduce some functionality to wait until all user were fetched, in order to return the response, and my code is likely to become a mess.
Store the complete user object - at least what I need for the comment (picture, name and such) in each comment. This redundancy could become troublesome to manage, since each time a user changes something (relevant to the data stored in the comments) I would have to go through all the comments in the database and modify it.
What is the correct pattern to apply here?
I tackled this exact problem a while ago.
There are no joins in mongo.
You have to manually take care of the join.
Your options are:
Loop through each comment entry and query mongo for the user. this is what you're doing.
Get all user id's from comments, query mongo for the users matching these ids, then take care to match user to comment.This is just what you did but a little more optimized.
Embed the user in comments or comments in users. Wouldn't recommend this, this is probably not the right place for comments/users.
Think of what set of data do you need from user when displaying a comment, and embed just this info in comment
I ended up going with the last option.
We embedded the user id, first and last name in each comment.
This info is unlikely to change (possibly not even allowed to change after creation?).
If it can change then it is not too hard to tailor the update-user method to update the related comments with the new info (we did that too).
So now no join is needed.

MongoEngine: How to collect embedded documents from referencing document

I have a class Post which has a list of embedded document called "comments"
Here all i want to do is to retrieve latest comments for all the posts user posted.
How can i achieve that? My current code, i just loop though the 'Post' class for that user and manually collect "comment".
But I also want this to be sorted by recently added, so have sort function to loop over manually collected comments and re-sort.
This seems like very inefficient, so asking for advise. Thanks!
Firstly if you $push onto the list with an update then you will keep the comments in order.
You can use the $slice operator to return the last x comments eg:
Post.objects(id=xxx).fields(slice__comments=-5)
However, the schema may not be efficient especially if you keep growing the number of comments, or comments can be unpublished. In that case you may want to split comments out into their own Document Model and link the comments to the Post by id. This would be two round trips to the database but offers more flexibility - eg. you could filter on date and published.

MongoDB ObjectId foreign key implementation recommendation

I'm looking for a recommendation on how best to implement MongoDB foreign key ObjectId fields. There seem to be two possible options, either containing the nested _id field or without.
Take a look at the fkUid field below.
{'_id':ObjectId('4ee12488f047051590000000'), 'fkUid':{'_id':ObjectId('4ee12488f047051590000001')} }
OR
{'_id':ObjectId('4ee12488f047051590000000'), 'fkUid':ObjectId('4ee12488f047051590000001')} }
Any recommendations would be much appreciated.
I'm having a hard time coming up with any possible advantages for putting an extra field "layer" in there, so I would personally just store the ObjectId directly in fkUid.
I suggest to use default dbref implementation, that is described here http://www.mongodb.org/display/DOCS/Database+References and is compatible with most of specific language drivers.
If your question is about the naming of the field (what you have in the title), usually the convention is to name it after the object to which it refers.
The both ways that you have mentioned are one of the same meaning. But they have different kind of usages.
Storing fkUid like 'fkUid':{'_id':ObjectId('4ee12488f047051590000001')} an object has it's own pros. Let me give an example, Suppose there is a website where users can post images and view images posted by other users as well. But when showing the image the website also shows the name/username of the user. By using this way you also can store the details like 'fkUid':{'_id':ObjectId('4ee12488f047051590000001'), username: 'SOME_X'}. When you are getting details from the db you don't have to send a request again to get the username for the specific _id.
Where as in the second way 'fkUid':ObjectId('4ee12488f047051590000001')} } you have to send another request to the server only for getting the name/username and nothing else is useful from the same object.