使用 $cond 切换更新管道中的嵌套数组值
Posted
技术标签:
【中文标题】使用 $cond 切换更新管道中的嵌套数组值【英文标题】:Toggle nested array value in update pipeline with $cond 【发布时间】:2022-01-07 10:10:06 【问题描述】:我正在尝试切换喜欢文档中 cmets 数组中评论的人的姓名。
比文字更形象化:Mongo Playground Link
解释:
假设我有一个文档
"id": 1,
"comments": [
"id": 1,
"text": "Comment 1",
"likedBy": [
"Tomato",
"Potato"
],
,
"id": 2,
"text": "Comment 2",
"likedBy": [
"Carrot"
],
,
],
,
我想在特定评论上“切换”likedBy
值“Potato”,与文档中的 comments.id
匹配。
到目前为止,我想出了这个
db.collection.update(
id: 1,
"comments.id": 1,
,
[
$set:
"comments.likedBy":
$cond: [
$in: [
"Potato",
"$comments.likedBy"
]
,
$setDifference: [
"$comments.likedBy",
[
"Potato"
]
]
,
$concatArrays: [
"$comments.likedBy",
[
"Potato"
]
]
],
,
,
])
预期输出:
"id": 1,
"comments": [
"id": 1,
"likedBy": [
"Tomato",
//!! Potato is removed from here
],
"text": "Comment 1"
,
"id": 2,
"likedBy": [
"Carrot"
],
"text": "Comment 2"
],
但是,我得到的结果不正确。我有一种感觉,我在使用位置运算符时做错了。
【问题讨论】:
您希望在 id=1、comment.id=1、likedBy 上添加“Potato”(如果缺少),或者删除“Potato”(如果存在)? 【参考方案1】:查询
这会从likeBy
中删除"Potato"
,如果它存在,则添加"Potato"
$map
在 cmets 上,如果 comment.id=1
添加/删除 "Potato"
否则留下评论
下面代码中$$this
是注释子文档
*不确定这是否正是您需要的,但会产生您想要的结果,并且看起来像您的查询。
*关于路径,“$cmets.likedBy”是一个数组,包含来自所有 cmets 的所有 likedBy
数组,$map
波纹管 $$this.likedBy
用于仅包含特定评论的 likedBy,我认为这是问题所在。
Test code here
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"]])
【讨论】:
在这种情况下,由于管道已经在检查"$eq": ["$$this.id", 1]
,从查找查询中删除"comments.id": 1
是否安全?
它不仅安全而且更好,保留它的唯一原因是如果你有太多的 id=1(我的意思是根 id)并且在comment.id
上有一个索引。我认为您不需要它,但我保留了它,因为我不知道您的数据如何。如果没有comment.id=1
,则查询永远不会更改评论,因此它是安全的
感谢您的解释。效果很好。以上是关于使用 $cond 切换更新管道中的嵌套数组值的主要内容,如果未能解决你的问题,请参考以下文章
带有 $cond 的 MongoDB 聚合管道 $addFields - 无法使用变量