交换MongoDB数组中的元素,只给出它们的id(原位)



我读了一些关于它的帖子,比如这个和那个,但是它们都有主要的缺陷& &;注意事项(至少对我来说)。

我要的很简单!更新查询:

  • 交换数组中的两个元素。
  • 每个元素是子文档
  • 我只给了两个索引作为输入,需要交换的。
  • 如果可能的话,我想避免使用javascript函数。
  • 我希望它是原子的!

这是我正在努力的部分:

选项1:使用update WITH聚合管道

(简介:在$arrayElemAt处成功,在"images.0"处失败)

db.users.update(
{ userID: 1 },
[
{ $set: { 
"images.0": { $arrayElemAt: ['$images', 2] },
"images.2": { $arrayElemAt: ['$images', 0] },
}}
]
)

如果我在更新中使用聚合,我可以访问$arrayElemAt操作符,这很好!但是这个解决方案失败了,因为这个→"images.0"也没有达到我的预期。我希望这样说"嘿,请覆盖图像内的第一个元素array"。但是不,它所做的是推动一个名为的新字段"0":{…},分配给images数组中的每个子文档。

选项2:使用update而不使用聚合管道

(简介:在"images.0"处成功,在$arrayElemAt处失败

db.users.update(
{ userID: 1 },
{ $set: { 
"images.0": { $arrayElemAt: ['$images', 2] },
"images.2": { $arrayElemAt: ['$images', 0] },
}}
)

这个失败了&成功的地方恰恰相反。
The "将第n个元素替换为给定的输入。
这里的问题是,因为它不再是一个聚合,所以我无法访问$arrayElemAt操作符,并且新的第n个元素简单地变为:

{
"$arrayElemAt" : [
"$aboutMe.images",
2.0
]
},

有谁知道我们能做什么吗?

这是一个我以前没有遇到过的好问题。这里的问题是,您需要一个管道来引用现有的值,但这阻止了使用点表示法甚至$push等直接索引。因此,一种选择是使用$reduce:

  1. $set所需值的键。
  2. $reduce参照$$value的大小,按此答案,以代替。
db.users.update(
{userID: 1},
[
{$set: {
firstItem: {$arrayElemAt: ["$images",  2]},
secondItem: {$arrayElemAt: ["$images", 0]}
}
},
{$set: {
images: {
$reduce: {
input: "$images",
initialValue: [],
in: {$concatArrays: [
"$$value",
{$cond: [
{$eq: [{$size: "$$value"}, 0]},
["$firstItem"],
{$cond: [{$eq: [{$size: "$$value"}, 2]}, 
["$secondItem"],
["$$this"]]
}
]
}
]
}
}
},
firstItem: "$$REMOVE",
secondItem: "$$REMOVE"
}
}
])

看看它在操场的例子中是如何工作的

最新更新