[英]Remove oldest N elements from document array
我的 mongodb 中有一个文档,其中包含一个非常大的数组(大约 10k 个项目)。 我试图只保留数组中最新的 1k(因此删除前 9k 个元素)。 该文件看起来像这样:
{
"_id" : 'fakeid64',
"Dropper" : [
{
"md5" : "fakemd5-1"
},
{
"md5" : "fakemd5-2"
},
...,
{
"md5": "fakemd5-10000"
}
]
}
我如何做到这一点?
此处要执行的正确操作实际上涉及使用$each
和$slice
修饰符的$push
运算符。 使用$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。所以你通常会与实际“添加”新元素一起使用像这样的项目:
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [{ "md5": "fakemd5-newEntry"}], "$slice": -1000 } }
)
这将附加$each
提供的新项目,同时还从数组的“开始”中删除任何项目,其中给定的总长度大于 1000。
在其他地方错误地说明您将使用$pullAll
并提供文档中已存在的数组内容列表,但该操作实际上是对数据库的两次请求。
误解是请求被发送为“一个”,但实际上不是,并且基本上被解释为较长的形式(正确使用.slice()
):
var md5s = db.collection.findOne({ "_id": "fakeid64" }).Dropper.slice(-1000);
db.collection.update(
{ "_id": "fakeid64" },
{ "$pullAll": { "Dropper": md5s } }
)
因此,您可以看到这不是很有效,并且实际上非常危险,当您考虑到文档中的数组状态“可能”在数组内容的“读取”和实际的“写入”操作之间“可能”发生变化时更新,因为它们分别发生。
这就是为什么 MongoDB 为$push
和$slice
提供原子操作符的原因,正如演示的那样。 由于它不仅效率更高,而且还考虑了实际修改发生时正在修改的文档的实际“状态”。
假设您使用 python/pymongo 驱动程序,您可以使用$pullAll运算符:
yourcollection.update_one(
{'_id': fakeid64},
{'$pullAll': {'Dropper': yourcollection.find_one({'_id': 'fakeid64'})['Dropper'][:9000]}}
)
或在 mongo shell 中:
db.yourcollection.update(
{ _id: 'fakeid64'},
{$pullAll: {'Dropper': db.yourcollection.findOne({'_id' : 'fakeid64'})['Dropper'].slice(0,9000)}}
)
(*) 话说如果你一开始就不允许你的文档增长这么多会更好
这只是查询的表示。 基本上你可以放松限制和跳过,然后使用光标 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} });
});
来自 mongo 文档
db.students.update( { _id: 1 }, { $push: { scores: { $each: [ { attempt: 3, score: 7 }, { attempt: 4, score: 4 } ], $sort: { score: 1 }, $slice: -3 } } } )
以下更新使用 $push 运算符:
将 $each 修饰符附加到数组 2 个新元素, $sort 修饰符按升序 (1) 分数对元素进行排序,以及 $slice 修饰符保留有序数组的最后 3 个元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.