I have a collection posts
which has an array of objects comments
. Within this array of objects, I have another array of objects likes
.
I am trying to write a query that pulls the most recent 5 comments from a post, and only pulls true
or false
for likes
, based on if the user has liked the comment already.
I have written this so far:
db.posts.aggregate([
{
"$match": {
"_id": postId
}
},
{
"$project":
{
"comments": {
"$slice": [ "$comments", -5 ]
}
}
},
{
"$project": {
"comments.content": 1,
"comments.likes": {
"$eq": [ "comments.likes.$.createdBy.username", username ]
}
}
}
])
But this seems to pull false
everytime.
Is it possible to do this without having to write a separate query to check if the user has liked?
EDIT: So for the below document:
With username = "testusername"
, and postId = "60fcd335abbe5a73583b69f0"
I would expect output:
[
{
"content": "test comment",
"likes": true
},
{
"content": "another test comment",
"likes": true
}
]
And with username = "testusername2"
I would expect output
[
{
"content": "test comment",
"likes": true
},
{
"content": "another test comment",
"likes": false
}
]
Thanks to @ray for your help with this one. Condensed Code Here though please see ray's response for the code split out with explanation.
You can use $map
to process your arrays layer-by-layer.
$map
comment to project a boolean for if the likes are liked by user1$anyElementTrue
to perform the checking on the projected booleandb.posts.aggregate([
{
"$match": {
"_id": "p1"
}
},
{
"$project": {
"comments": {
"$slice": [
"$comments",
-5
]
}
}
},
{
"$project": {
likes: {
"$map": {
"input": "$comments",
"as": "c",
"in": {
content: "$$c.content",
likedByU1: {
"$map": {
"input": "$$c.likes",
"as": "l",
"in": {
$eq: [
"$$l.createdBy._id",
"u1"
]
}
}
}
}
}
}
}
},
{
"$project": {
likes: {
"$map": {
"input": "$likes",
"as": "l",
"in": {
content: "$$l.content",
likedByU1: {
"$anyElementTrue": [
"$$l.likedByU1"
]
}
}
}
}
}
}
])
Here is the Mongo playground to show the idea(with some minor modifications to your example). You can modify it to fit your needs.