假设我有一份文件如下:
doc = {
"_id" : ObjectId("56464c726879571b1dcbac79"),
"food" : {
"fruit" : [
"apple",
"orange"
]
},
"items" : [
{
"item_id" : 750,
"locations" : [
{
"store#" : 13,
"num_employees" : 138
},
{
"store#" : 49,
"num_employees" : 343
}
]
},
{
"item_id" : 650,
"locations" : [
{
"store#" : 12,
"num_employees" : 22
},
{
"store#" : 15,
"num_employees" : 52
}
]
}
]
}
我想删除元素
{'#store#' : 12, 'num_employees' : 22}
但仅当满足以下条件时:
food.fruit
包含值apple
或orange
item_id
的ID为650
我尝试了以下内容:
db.test.update({"food.fruit" : {"$in" : ["apple", "orange"]}, "items.item_id":650},{$pull:{'items.$.locations':{'store#':12,'num_employees':22}}})
更新不起作用。有趣的是,如果查询的$ in运算符部分被删除,它就可以工作。我正在使用MongoDB v3.0.6并查阅MongoDB手册以使用 $(更新):
https://docs.mongodb.org/manual/reference/operator/update/positional/
文档包含一段感兴趣的内容:
Nested Arrays
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value
我的查询当然遍历多个数组。实际上,如果我从查询中删除'food.fruit' : {$in : ['apple']}
,它就会起作用。但是,这样做
不解决我的问题,因为我当然需要那个查询。我正在寻找一个最好的解决方案:
答案 0 :(得分:1)
如果您需要匹配"food.fruit"
中的多个可能值以及其他多个可能的文档(唯一有意义的情况),那么您始终可以使用JavScript逻辑替换$in
在$where
中:
db.test.update(
{
"items.item_id": 650,
"$where": function() {
return this.food.fruit.some(function(el) {
return ["apple","orange"].indexOf(el) != -1;
});
}
},
{ "$pull": { "items.$.locations": { "store#": 12 } } },
{ "multi": true }
)
基本上应用相同的测试,虽然效率不如"food.fruit"
值无法在索引中测试,但希望"items.item_id
"至少是不足以使这成为一个真正的问题。
另一方面,针对MongoDB服务器版本3.1.9(开发系列)进行测试,以下工作没有问题:
db.test.update(
{ "food.fruit": { "$in": ["orange","apple"] }, "items.item_id": 650 },
{ "$pull": { "items.$.locations": { "store#": 12 } } },
{ "multi": true }
)
我还建议,如果您打算在查询中包含_id
,那么无论如何您只匹配单个文档,因此您只需要在您想要的数组上提供匹配{{ 3}}来自:
db.test.update(
{ "_id": 123, "items.item_id": 650 },
{ "$pull": { "items.$.locations": { "store#": 12 } } }
)
这非常简单并且没有冲突,除非您确实需要以确保实际存在所需的"food.fruits"
值才能应用更新。在这种情况下,请遵循前面的例子。
答案 1 :(得分:0)
马特,
我使用了您的示例数据,以下查询有效:
db.pTest.update(
{"food.fruit" : "apple","items.item_id":650},
{$pull:{'items.$.locations':{'store#':12,'num_employees':22}}}
)
不需要$in
(除非您为数组输入多个值),也不需要$elemMatch
。此外,对于两级深度数组,您可以使用{$pull: {"someArray.$.someNestedArray": {"key": "value to delete"}}}
。
您从文档中引用的内容。
嵌套数组 位置$运算符不能用于遍历多个数组的查询,例如遍历嵌套在其他数组中的数组的查询,因为$ placeholder的替换是单个值。
转换为,意味着您无法使用$ Positional
运算符两次。
示例数据:
{
"_id" : ObjectId("56464c726879571b1dcbac79"),
"food" : {
"fruit" : [
"apple",
"orange"
]
},
"items" : [
{
"item_id" : 650,
"locations" : [
{
"store#" : 12,
"num_employees" : 22
},
{
"store#" : 15,
"num_employees" : 52
}
]
}
]
}
结果:
{
"_id" : ObjectId("56464c726879571b1dcbac79"),
"food" : {
"fruit" : [
"apple",
"orange"
]
},
"items" : [
{
"item_id" : 650,
"locations" : [
{
"store#" : 15,
"num_employees" : 52
}
]
}
]
}