0

I want to create a system of user reviews and replies to the reviews in a website. There can be replies to replies. I'm using mongodb database which I think is an important detail.

The review document looks roughly like this:

{
  review: {
    reviewid: String,
    userid: String,
    reviewRating: Int,
    reviewContent: String,
    replies: [Reply]
  }

}

The reply object looks like this:

{
  reply: {
    userid: String,
    reviewid: String,
    replyid: String,
    replyContent: String
  }
}

I'm not sure which route to take with how to store user replies. On the one hand it will be super convenient to store an array of reply objects in the review document (1). On the other hand I feel it will be more stable and organized to save replies as separate documents in the db (2).

In case 1 I get the benefit of mongodb flexibility and I will not need to make db lookups.

In case 2 I thought to add previous: ObjectId and next: ObjectId fields to each reply. Then the review will only be linked to the first reply in the chain. In case 2 there will be more lookups for replies as I will have to iterate next all the time. It won't take a lot of time to get the next reply though because mongodb creates an index by default on id fields. Another disadvantage is that in order to count the number of replies per review I will need to make as many db lookups to db as there're replies unless I keep the count as a field in review and make sure to increment/decrement it each time (more complexity).

So on the face of it the first route is better in terms of performance. The main disadvantage of it is that replies order is a bit volatile in the sense that it's just an array. I also instinctively feel the first route is "flimsy" because the replies are not an actual document in the db without their own id.

I'm looking for suggestions on what the best practice would be here.

2

You should store the replies as its own document because you can get scaling problems if storing with the review. This is an important part of DDD where it is called a consistency boundary.

I assume you want multiple users to be able to post a reply independently of each other. If you are storing them together you can risk some replies fail just because another user posted a reply at the same time which doesn't make any sense.

Also if there suddenly comes a big number of replies for a review your system would have to handle maybe 1000 replies in the same document which is not ideal either.

  • Why if there're 2 users who want to make a reply simultaneously there's a risk of failure? Mongo will queue subsequent updates for a given document (dba.stackexchange.com/a/175007/156795) – Yos Jan 14 at 7:32
  • The question is not tagged with mongodb but with generic document-databases tags so I applied a general approach where I assume normal optimistic concurrency. I don't know how mongo does it in this case. Would it just overwrite the first update or try and do a complicated merge. In either case it is a problem that goes away when saving separately – Esben Skov Pedersen Jan 14 at 7:57
0

While I aggree with Esben, that from a domain perspective the replies should be separate objects, you specifically ask about mongo, which is a totally different beast. For mongo, you should design your database not by looking at the storage of objects, but at the queries you make.

That being said, when you need to query a review together with its replies, to show them in one page, you should definitely store them in a single object. This does not necessarily mean, that this is the only place where you store the replies. (Redundancy is OK in mongodb - this is not a relational database!)

What you still have to think about is, what happens when the single document gets too large. (There still is the limit of 16 MB per document.) A common pattern is having a continuation marker, i.e.

{
    review: {
        reviewid: 00001,
        is_main_document: true,
        replies: [...],
        more_replies: 00002
},
{
    review: {
        reviewid: 00002,
        ismaindocument: false,
        replies: [...]
}

This priniciple continues on to other aspects. E.g. you have a userid in your reply object. If you actually want to display the name and city of the user, you should add a user_name and user_location there, so that you don't have to do additional database roundtrips when reading.

If a user moves to a different city, then yes, you'll have to update maybe 1000 documents. This is OK. In mongo, optimize for the normal case. And for most web applications, this means, optimize for the normal reading page-impression, which occurs a millon times more than actual data changes.

If you start to cringe now (which I understand, starting out with mongo I also did that), there's two basic possibilities:

  • use a relational database instead
  • add another layer, i.e. keep your reviews and replies in separate objects/collections, and add a view-presentation object, which you rebuild every time a change in either review or reply occurs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.