我在MongoDB(2.4.5)中有以下文档
{
"_id" : 235399,
"casts" : {
"crew" : [
{
"_id" : 1186343,
"withBase" : true,
"department" : "Directing",
"job" : "Director",
"name" : "Connie Rasinski"
},
{
"_id" : 86342,
"withBase" : true
}
]
},
"likes" : 0,
"rating" : 0,
"rating_count" : 0,
"release_date" : "1955-11-11"
}
我想从casts.crew ..
中的数组元素中删除withBase我试过这个
db.coll.update({_id:235399},{$unset: { "casts.crew.withBase" : 1 } },false,true)
没有改变。
并尝试了这个..
db.coll.update({_id:235399},{$unset: { "casts.crew" : { $elemMatch: { "withBase": 1 } } } },false,true)
它从文档中删除了整个工作人员阵列。
有人可以提供正确的查询吗?
答案 0 :(得分:44)
很抱歉让你失望,但你的回答
db.coll.update({
_id:235399,
"casts.crew.withBase": {$exists: true}
},{
$unset: {
"casts.crew.$.withBase" : true
}
},false,true)
不正确。实际上它会删除值,但仅从第一次出现的子文档中删除,因为positional operator works的方式:
位置$运算符充当第一个元素的占位符 与查询文档匹配
您也无法使用$unset
(正如您之前尝试过的那样),因为它无法在数组上运行(您基本上是尝试从数组中删除文档中的键)。你也无法用$pull
删除它,因为pull会删除所有数组,而不仅仅是它的一个字段。
因此据我所知,你不能用一个简单的算子来做到这一点。所以最后的办法是$find
,然后forEach
进行保存。你可以看到how to do this in my answer here。在您的情况下,您需要在forEach
函数中使用另一个循环来迭代数组并转到delete a key。我希望你能修改它。如果不是,我会尽力帮助你。
P.S。如果有人想要这样做 - 这里是 Sandra的功能
db.coll.find({_id:235399}).forEach( function(doc) {
var arr = doc.casts.crew;
var length = arr.length;
for (var i = 0; i < length; i++) {
delete arr[i]["withBase"];
}
db.coll.save(doc);
});
答案 1 :(得分:29)
您可以使用新的positional identifier
更新3.6中的数组中的多个元素。
像
这样的东西 db.coll.update( {_id:235399}, {$unset: {"casts.crew.$[].withBase":""}} )
$[]从withBase
数组中删除所有crews
属性。它充当占位符,用于更新数组中的所有元素。
使用multi true可影响多个文档。
答案 2 :(得分:13)
我找到了一种方法来取消设置这个列表,而不必拉起对象(意思是,只是做一次更新),这是非常hackish但是如果你有一个庞大的数据库它将会达成协议:
db.coll.update({},{$unset: {"casts.crew.0.withBase" : 1, "casts.crew.1.withBase" : 1} }, {multi: 1})
换句话说,您必须计算任何文档列表中可以有多少个对象,并明确添加这些数字,在本例中为{casts.crew.NUMBER.withBase: 1}
。
另外,要计算mongodb对象中最长的数组,可以进行聚合,如下所示:
db.coll.aggregate( [ { $unwind : "$casts.crew" }, { $group : { _id : "$_id", len : { $sum : 1 } } }, { $sort : { len : -1 } }, { $limit : 1 } ], {allowDiskUse: true} )
只是想强调这不是一个漂亮的解决方案,但比获取和保存更快。