我的 mongodb 中有一个文档,其中包含一个非常大的数组(大约 10k 个项目)。我试图只保留数组中最新的 1k(因此删除前 9k 元素)。该文档看起来像这样:
{
"_id" : 'fakeid64',
"Dropper" : [
{
"md5" : "fakemd5-1"
},
{
"md5" : "fakemd5-2"
},
...,
{
"md5": "fakemd5-10000"
}
]
}
Run Code Online (Sandbox Code Playgroud)
我该如何做到这一点?
这里执行的正确操作实际上涉及$push使用$eachand$slice修饰符的运算符。这种用法最初可能看起来违反直觉,您将使用它$push来从数组中“删除”项目,但当您看到预期的操作时,实际用例就很清楚了。
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } }
)
Run Code Online (Sandbox Code Playgroud)
事实上,你可以运行你的整个集合:
db.collection.update(
{ },
{ "$push": { "Dropper": { "$each": [], "$slice": -1000 } },
{ "multi": true }
)
Run Code Online (Sandbox Code Playgroud)
这里发生的情况是,修饰符 for$each接受一个要在操作中“添加”的项目数组$push,在本例中我们将其保留为空,因为我们实际上不想添加任何内容。给出“负”值的修饰符$slice实际上是说在执行更新时保留数组中存在的“最后 n”个元素,这正是您所要求的。
一般的“预期”情况是在添加新元素以“维护”数组的“最大”给定长度时使用$slice,在本例中为 1000。因此,您通常会与实际“添加”新项目一起使用,例如这:
db.collection.update(
{ "_id": "fakeid64" },
{ "$push": { "Dropper": { "$each": [{ "md5": "fakemd5-newEntry"}], "$slice": -1000 } }
)
Run Code Online (Sandbox Code Playgroud)
这将追加提供的新项目,$each同时还会从数组的“开始”处删除任何项目,其中添加的总长度大于 1000。
在其他地方错误地指出,您将使用$pullAll文档中已存在的数组内容的提供列表,但该操作实际上是对数据库的两个请求。
误解是请求作为“一”发送,但实际上不是,并且基本上被解释为更长的形式(正确使用.slice()):
var md5s = db.collection.findOne({ "_id": "fakeid64" }).Dropper.slice(-1000);
db.collection.update(
{ "_id": "fakeid64" },
{ "$pullAll": { "Dropper": md5s } }
)
Run Code Online (Sandbox Code Playgroud)
因此,您可以看到,当您考虑到文档中数组的状态“可能”在数组内容的“读取”和实际的“写入”操作之间发生变化时,这不是很有效,而且实际上非常危险更新时,因为它们是单独发生的。
这就是为什么 MongoDB 有$pushwith原子运算符$slice,如所示。因为它不仅效率更高,而且还考虑到实际修改发生时正在修改的文档的实际“状态”。
| 归档时间: |
|
| 查看次数: |
1890 次 |
| 最近记录: |