Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse Server, MongoDB - get "liked" state of an object

I am using Parse Server, which runs on MongoDB.

Let's say I have collections User and Comment and a join table of user and comment. User can like a comment, which creates a new record in a join table.

Specifically in Parse Server, join table can be defined using a 'relation' field in the collection.

Now when I want to retrieve all comments, I also need to know, whether each of them is liked by the current user. How can I do this, without doing additional queries?

You might say I could create an array field likers in Comment table and use $elemMatch, but it doesn't seem as a good idea, because potentially, there can be thousands of likes on a comment.

My idea, but I hope there could be a better solution:

I could create an array field someLikers, a relation (join table) field allLikers and a number field likesCount in Comment table. Then put first 100 likers in both someLikers and allLikers and additional likers only in the allLikers. I would always increment the likesCount.

Then when querying a list of comments, I would implement the call with $elemMatch, which would tell me whether the current user is inside someLikers. When I would get the comments, I would check whether some of the comments have likesCount > 100 AND $elemMatch returned null. If so, I would have to run another query in the join table, looking for those comments and checking (querying by) whether they are liked by the current user.

Is there a better option?

Thanks!

like image 791
David Riha Avatar asked Jan 14 '18 10:01

David Riha


2 Answers

I'd advise agains directly accessing MongoDB unless you absolutely have to; after all, the way collections and relations are built is an implementation detail of Parse and in theory could change in the future, breaking your code.

Even though you want to avoid multiple queries I suggest to do just that (depending on your platform you might even be able to run two Parse queries in parallel):

  1. The first one is the query on Comment for getting all comments you want to display; assuming you have some kind of Post for which comments can be written, the query would find all comments referencing the current post.
  2. The second query again is for on Comment, but this time
    • constrained to the comments retrieved in the first query, e.g.: containedIn("objectID", arrayOfCommentIDs)
    • and constrained to the comments having the current user in their likers relation, e.g.: equalTo("likers", currentUser)
like image 87
dr_barto Avatar answered Oct 23 '22 07:10

dr_barto


Well a join collection is not really a noSQL way of thinking ;-) I don't know ParseServer, so below is just based on pure MongoDB.

What i would do is, in the Comment document use an array of ObjectId's for each user who likes the comment.

Sample document layout

{ 
    "_id" : ObjectId(""), 
    "name" : "Comment X", 
    "liked" : [
        ObjectId(""), 
        ....
    ]
}

Then use a aggregation to get the data. I asume you have the _id of the comment and you know the _id of the user.

The following aggregation returns the comment with a like count and a boolean which indicates the user liked the comment.

db.Comment.aggregate(

    [
        {
            $match: {
            _id : ObjectId("your commentId")
            }
        },
        {
            $project: {
                _id : 1,
                name :1,
                number_of_likes : {$size : "$liked"},
                user_liked: {
                            $gt: [{
                                $size: {
                                    $filter: {
                                        input: "$liked",
                                        as: "like",
                                        cond: {
                                            $eq: ["$$like", ObjectId("your userId")]
                                        }
                                    }
                                }
                            }, 0]
                        },
            }
        },
    ]
);

this returns

{ 
"_id" : ObjectId(""), 
"name" : "Comment X", 
"number_of_likes" : NumberInt(7), 
"user_liked" : true

}

Hope this is what your after.

like image 2
HoefMeistert Avatar answered Oct 23 '22 09:10

HoefMeistert