I am trying to toggle names of people who liked a comment in the comments array in a document.
Better visualized than words: Mongo Playground Link
Explanation:
Suppose I have a document
{
"id": 1,
"comments": [
{
"id": 1,
"text": "Comment 1",
"likedBy": [
"Tomato",
"Potato"
],
},
{
"id": 2,
"text": "Comment 2",
"likedBy": [
"Carrot"
],
},
],
},
I would like to "toggle" a likedBy
value "Potato" on a particular comment, matched by comments.id
in a document.
So far, I came up with this
db.collection.update({
id: 1,
"comments.id": 1,
},
[
{
$set: {
"comments.likedBy": {
$cond: [
{
$in: [
"Potato",
"$comments.likedBy"
]
},
{
$setDifference: [
"$comments.likedBy",
[
"Potato"
]
]
},
{
$concatArrays: [
"$comments.likedBy",
[
"Potato"
]
]
}
],
},
},
}
])
Expected output:
{
"id": 1,
"comments": [
{
"id": 1,
"likedBy": [
"Tomato",
//!! Potato is removed from here
],
"text": "Comment 1"
},
{
"id": 2,
"likedBy": [
"Carrot"
],
"text": "Comment 2"
}
],
}
However, I am getting incorrect result. I have a feeling that I am doing something wrong with the positional operators.
CodePudding user response:
Query
- this removes the
"Potato"
fromlikeBy
if it exists else adds the"Potato"
$map
on comments, ifcomment.id=1
add/remove the"Potato"
else leave comment as it is- in the bellow code
$$this
is the comment sub-document
*Not sure if this is what you need exactly but produces the result you want, and looks like your query.
*about the paths, "$comments.likedBy" is an array that contains all the likedBy
arrays from all comments, with $map
bellow $$this.likedBy
is used to contain only the likedBy of a specific comment, i think this was the problem.
update(
{"id": 1,"comments.id": 1},
[{"$set":
{"comments":
{"$map":
{"input": "$comments",
"in":
{"$cond":
[{"$eq": ["$$this.id", 1]},
{"$mergeObjects":
["$$this",
{"likedBy":
{"$cond":
[{"$in": ["Potato", "$$this.likedBy"]},
{"$setDifference": ["$$this.likedBy", ["Potato"]]},
{"$concatArrays": ["$$this.likedBy", ["Potato"]]}]}}]},
"$$this"]}}}}}])