设置为0,通过id查询获取文档的items.qty。
db.warehouses.update(
// query
{
_id:ObjectId('5322f07e139cdd7e31178b78')
},
// update
{
$set:{"items.$.qty":0}
},
// options
{
"multi" : true, // update only one document
"upsert" : true // insert a new document, if no existing document match the query
}
);
返回:
如果没有包含数组的相应查询字段,则无法应用位置运算符。
这是我想将所有items.qty设置为0
的文档{
"_id": { "$oid" : "5322f07e139cdd7e31178b78" },
"items": [
{
"_id": { "$oid" : "531ed4cae604d3d30df8e2ca" },
"brand": "BJFE",
"color": "GDRNCCD",
"hand": 1,
"model": 0,
"price": 500,
"qty": 0,
"type": 0
},
{
"brand": "BJFE",
"color": "GDRNCCD",
"hand": 1,
"id": "23",
"model": 0,
"price": 500,
"qty": 4,
"type": 0
},
{
"brand": "BJFE",
"color": "GDRNCCD",
"hand": 1,
"id": "3344",
"model": 0,
"price": 500,
"qty": 6,
"type": 0
}
],
"name": "a"
}
答案 0 :(得分:4)
问题中缺少的细节是要更新的必填字段实际上是在子文档中。这大大改变了答案:
这是对可能更新数组元素的约束。 documentation清楚地解释了这一点。主要在本段中:
位置$运算符充当与查询文档匹配的第一个元素的占位符
所以这就是事情。尝试在像这样的单个语句中更新所有数组元素不工作。为此,您必须执行以下操作。
db.warehouses.find({ "items.qty": { "$gt": 0 } }).forEach(function(doc) {
doc.items.forEach(function(item) {
item.qty = 0;
});
db.warehouses.update({ "_id": doc._id }, doc );
})
这基本上是更新每个数组元素的方法。
.update()
中的多设置表示多个"文档"。 不能应用于数组的多个元素。所以目前最好的选择是取代整个事物。或者在这种情况下,我们也可以替换整个文档,因为无论如何我们都需要这样做。
对于真实批量数据,请使用db.eval()。但请先阅读文档:
db.eval(function() {
db.warehouses.find({ "items.qty": { "$gt": 0 } }).forEach(function(doc) {
doc.items.forEach(function(item) {
item.qty = 0;
});
db.warehouses.update({ "_id": doc._id }, doc );
});
})
在整个集合中更新所有数组中的元素并不简单。
几乎就是错误所说的。要使用位置运算符,您需要先匹配。如:
db.warehouses.update(
// query
{
_id:ObjectId('5322f07e139cdd7e31178b78'),
"items.qty": { "$gt": 0 }
},
// update
{
$set:{"items.$.qty":0}
},
// options
{
"multi" : true,
"upsert" : true
}
);
因此匹配条件会在小于 0的项目中位置,然后索引被传递给位置操作员。
P.S :当 muti true 时,表示它会更新每个文档。如果你只是指一个,请保留false
。这是默认值。
答案 1 :(得分:2)
只有在第一个参数中指定数组时才能使用$ positional operator(即,用于标识要更新的文档的查询部分)。
位置$运算符标识要更新的数组字段中的元素,而不显式指定元素在数组中的位置。