I have a mongoose model for a “social media like post” (called PostModel) that has this schema:
{ caption: String, comments: [ { comment: String, // basically an array to store all those who liked the comment likedBy: [...] // array of references to a different model }, ... // more comment objects like this ] }
I simply want to know the number of likes each comment got when querying for a post. This should not be as annoying and difficult as it is. I have spent more than 4 hours on this.
What I have tried so far:
Attempt 1:
PostModel.findById(postId, { "comments.likes": { $size: "$comment.likedBy" } // gives the number of comments instead of the number of likes on the comment })
Attempt 2:
PostModel.findById(postId, { "comments.likes": { $size: "$likedBy" } // gives "likedBy not defined" error })
Attempt 3:
PostModel.findById(postId, { "comments.likes": { $size: "$comments.$likedBy" } // gives "FieldPath field names may not start with '$'. Consider using $getField or $setField" error })
Attempt 4:
PostModel.findById(postId, { "comments.likes": { $size: "$comments.$.likedBy" } // gives "FieldPath field names may not start with '$'. Consider using $getField or $setField" error })
I basically want to access the “current element” in this “forEach” like array traversal. For example:
const a = [{likes: ["x", "y"]}, {likes: ["a", "b"]}, {likes: []}]; a.forEach((element, index) => { console.log(element.likes.length) // this is what I want but for mongoDB }) // output: 2 2 0
I have looked everywhere but could not find a solution even after searching for 4 hours. Anything that would point me even remotely near the current direction would be helpful.
I do not want to load the entire comments array into memory just to get the lengths of the nested likedBy arrays. Otherwise this would not even be a problem.
Advertisement
Answer
In case you want to get total number of likes from all comments
you can use $reduce operator:
{ $project: { likes: { $reduce: { input: "$comments", initialValue: 0, in: { $add: [ "$$value", { $size: "$$this.likedBy" } ] } } } } }
Alternatively you may need $map to enrich each comment with a number of likes:
{ $project: { comments: { $map: { input: "$comments", in: { $mergeObjects: [ "$$this", { $numberOfLikes: { $size: "$$this.likedBy" } } ] } } } } }