我有一个集合,可以将这些元素简化为:
{tags : [1, 5, 8]}
其中数组中至少有一个元素,所有元素都应该不同。我想用一个标签替换另一个标签,我认为不会有问题。所以我提出了以下问题:
db.colll.update({
tags : 1
},{
$pull: { tags: 1 },
$addToSet: { tags: 2 }
}, {
multi: true
})
很酷,所以它会找到所有带有我不需要的标签的元素(1),删除它并添加另一个(2)如果它不存在。问题是我收到错误:
"无法更新'标签'和'标签'在同一时间"
这基本上意味着我不能同时做pull和addtoset。有没有其他方法可以做到这一点?
当然我可以记住元素的所有ID,然后删除标记并添加单独的查询,但这听起来不太好。
答案 0 :(得分:16)
错误几乎就是它的意思,因为你不能在同一个更新操作中对同一个“路径”的两个东西进行操作。您正在使用的两个运算符不会像您认为的那样按顺序处理。
您可以使用"bulk" operations API或其他形式的“批量”更新,以“顺序”方式执行此操作。在理由当然,也是相反的:
var bulk = db.coll.initializeOrderedBulkOp();
bulk.find({ "tags": 1 }).updateOne({ "$addToSet": { "tags": 2 } });
bulk.find({ "tags": 1 }).updateOne({ "$pull": { "tags": 1 } });
bulk.execute();
不保证没有其他任何东西可以尝试修改,但它与您目前的距离非常接近。
另请参阅包含多个文档的原始"update" command。
答案 1 :(得分:5)
如果您要同时删除和添加,则可能会对地图进行建模,而不是设置'。如果是这样,对象的工作可能少于数组。
而不是数据作为数组:
{ _id: 'myobjectwithdata',
data: [{ id: 'data1', important: 'stuff'},
{ id: 'data2', important: 'more'}]
}
将数据用作对象:
{ _id: 'myobjectwithdata',
data: { data1: { important: 'stuff'},
data2: { important: 'more'} }
}
单命令更新是:
db.coll.update(
'myobjectwithdata',
{ $set: { 'data.data1': { important: 'treasure' } }
);
答案 2 :(得分:2)
从Mongo 4.4
开始,$function
聚合运算符允许应用自定义javascript函数来实现MongoDB查询语言不支持的行为。
并结合Mongo 4.2
中对db.collection.update()
的改进,可以接受聚合管道,从而允许根据字段自身的值更新字段
我们可以使用语言不容易允许的方式来操纵和更新数组:
// { "tags" : [ 1, 5, 8 ] }
db.collection.updateMany(
{ tags: 1 },
[{ $set:
{ "tags":
{ $function: {
body: function(tags) { tags.push(2); return tags.filter(x => x != 1); },
args: ["$tags"],
lang: "js"
}}
}
}]
)
// { "tags" : [ 5, 8, 2 ] }
$function
具有3个参数:
body
,这是要应用的函数,其参数是要修改的数组。这里的功能仅包括push
将2
放入数组并filter
取出1
。args
,其中包含body
函数作为参数的记录中的字段。在我们的情况下,"$tag"
。lang
,这是编写body
函数的语言。当前仅js
可用。答案 3 :(得分:0)
如果您需要将数组中的一个值替换为另一个,请检查以下答案: