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.
CodePudding user response:
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" } }
]
}
}
}
}
}