我的mongodb中有一个包含非常大的数组(大约10k项)的文档。我试图只保留阵列中最新的1k(因此删除前9k元素)。该文件看起来像这样:
{
"_id" : 'fakeid64',
"Dropper" : [
{
"md5" : "fakemd5-1"
},
{
"md5" : "fakemd5-2"
},
...,
{
"md5": "fakemd5-10000"
}
]
}
我如何做到这一点?
答案 0 :(得分:1)
您可以使用$pullAll运算符 假设您使用python / pymongo驱动程序:
db.yourcollection.update(
{ _id: 'fakeid64'},
{$pullAll: {'Dropper': db.yourcollection.findOne({'_id' : 'fakeid64'})['Dropper'].slice(0,9000)}}
)
或在mongo shell中:
String
(*)说如果你不允许你的文件在第一时间增长那么会好得多
答案 1 :(得分:0)
这只是查询的表示。基本上你可以使用限制和跳过来放松,然后使用光标foreach删除下面的项目:
db.your_collection.aggregate([
{ $match : { _id : 'fakeid64' } },
{ $unwind : "$Dropper"},
{ $skip : 1000},
{ $limit : 9000}
]).forEach(function(doc){
db.your_collection.update({ _id : doc._id}, { $pull : { Dropper : doc.Dropper} });
});
答案 2 :(得分:0)
在此处执行的正确操作实际上涉及使用$push
和$each
修饰符的$slice
运算符。最初使用可能会违反直觉,您可以使用$push
来删除"数组中的项目,但是当您看到预期的操作时,实际的用例是明确的。
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } }
)
事实上,您可以按以下方式运行整个集合:
db.collection.update(
{ },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } },
{ "multi": true }
)
这里发生的是$each
的修饰符将一系列项目带到"添加"在$push
操作中,在这种情况下,我们留空,因为我们实际上并不想添加任何内容。 $slice
修饰符给出了"否定"价值实际上是说保持"最后n"在执行更新时,数组中存在元素,这正是您所要求的。
将军"意图"案例是在向"维护"添加新元素时使用$slice
。数组在"最大值"给定长度,在这种情况下为1000.因此,您通常会与实际使用#34;添加"像这样的新项目:
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [{ "md5": "fakemd5-newEntry"}], "$slice": -1000 } }
)
这将追加$each
中提供的新项目,同时还删除" start"中的所有项目。添加的总长度大于1000的阵列。
其他地方的说法不正确,您将$pullAll
与文档中已存在的数组内容的提供列表一起使用,但该操作实际上是对数据库的两个请求。
误解是请求以" one"发送,但它实际上不是,并且基本上被解释为更长的形式(正确使用.slice()
):
var md5s = db.collection.findOne({ "_id": "fakeid64" }).Dropper.slice(-1000);
db.collection.update(
{ "_id": "fakeid64" },
{ "$pullAll": { "Dropper": md5s } }
)
因此,当您考虑到文档中数组的状态时,您可以看到这不是非常有效并且实际上非常危险 34>可能会改变"读"数组内容和实际的#34;写"更新操作,因为它们是分开发生的。
这就是为什么MongoDB具有$push
$slice
的原子运算符,正如所展示的那样。因为它不仅更有效率,而且还考虑到实际的状态"在实际修改发生时修改的文件。