Bab*_*yan 4 mongodb aggregation-framework
如何删除chunks作为此聚合结果返回的所有文档?
db.getCollection('chunks').aggregate([
{
$lookup:
{
from: "files",
localField: "files_id",
foreignField: "_id",
as: "file"
}
},
{
$match:
{
"file.uploadDate":
{
$lt: ISODate("2017-06-10T00:00:00.000Z")
}
}
}
])
Run Code Online (Sandbox Code Playgroud)
我的架构有一个名为 的集合files,其中包含文件元数据(名称、上传日期)和块,其中包含实际数据(二进制、files_id)
但是我知道db.collection.deleteMany({})它只接受匹配过滤器。
我有 MongoDB 3.2
循环结果:
var ops = [];
db.getCollection('chunks').aggregate([
{
$lookup:
{
from: "files",
localField: "files_id",
foreignField: "_id",
as: "file"
}
},
{
$match:
{
"file.uploadDate":
{
$lt: ISODate("2017-06-10T00:00:00.000Z")
}
}
}
]).forEach(doc => {
ops = [
...ops,
{ "deleteOne": {
"filter": { "_id": doc._id }
}}
];
if ( ops.length >= 1000 ) {
db.getCollection('chunks').bulkWrite(ops);
ops = [];
}
});
if ( ops.length > 0 ) {
db.getCollection('chunks').bulkWrite(ops);
ops = [];
}
Run Code Online (Sandbox Code Playgroud)
或者在没有 ES6 的环境中:
var ops = [];
db.getCollection('chunks').aggregate([
{
$lookup:
{
from: "files",
localField: "files_id",
foreignField: "_id",
as: "file"
}
},
{
$match:
{
"file.uploadDate":
{
$lt: ISODate("2017-06-10T00:00:00.000Z")
}
}
}
]).forEach(function(doc) {
ops.push({ "deleteOne": { "filter": { "_id": doc._id } } });
if ( ops.length >= 1000 ) {
db.getCollection('chunks').bulkWrite(ops);
ops = [];
}
});
if ( ops.length > 0 ) {
db.getCollection('chunks').bulkWrite(ops);
ops = [];
}
Run Code Online (Sandbox Code Playgroud)
使用.bulkWrite()然后你基本上是“批处理”1000 个请求。所以来自数据库的实际写入和响应只发生在那个时候,而不是所有条目。
您不能提供聚合管道作为通用.remove**()方法的查询参数。所以你要做的是用这样的动作循环光标。
获得聚合结果后,您可以使用map函数来获取所有chunk ID,然后您可以使用db.collection.remove()with$in运算符。
var pipeline = [
{$lookup:{
from: "files",
localField: "files_id",
foreignField: "_id",
as: "file"
}
},
{$match:{
"file.uploadDate":
{
$lt: ISODate("2017-06-10T00:00:00.000Z")
}
}
}
];
var cursor = db.chunks.aggregate(pipeline);
var chunkIds = cursor.map(function (chunk) { return chunk._id; });
db.chunks.remove({"_id": { "$in": chunkIds }});
Run Code Online (Sandbox Code Playgroud)
另一种方法有点 hacky,即将计算转移到 mongodb,而不是通过 Node.js 应用程序运行列表。然而,这需要对数据库中的数据进行一些临时更改。
简单的逻辑是这样的:
注意:我正在为最新版本的 mongodb 编写代码,$merge根据文档,我所依赖的步骤至少可以从 4.2 版本获得,但不能从 4.0 或更早版本获得。这个答案对原始问题中使用的版本 3.2 没有帮助,但我认为值得在这里添加它,因为这个问题+答案通常会显示在对该问题的搜索中。
// .toArray() at the end triggers mongodb to execute the merge step - even though it doesn't return anything.
// await makes sure we wait until all items are marked before continuing.
await db.collection("chunks").aggregate([
// The lookup and matching as before
{ $lookup: { from: "files", localField: "files_id", foreignField: "_id", as: "files" } },
{ $match: { "files.uploadDate": { $lt: ISODate("2017-06-10T00:00:00.000Z") } } },
// Remove the files field added by the lookup, no longer needed
{ $removeField: "files" },
// Mark for deletion by setting a field
{ $set: { __markedForDeletion: true } },
// Overwrite chunks entries with the deletion marking
{ $merge: { into: "chunks", whenMatched: "replace" } },
]).toArray();
Run Code Online (Sandbox Code Playgroud)
await db.collection("chunks").deleteMany({ __markedForDeletion: true });
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是不需要 mongodb 序列化并将数据发送到 Node.js 应用程序,只需等待 mongodb 在内部执行命令,这比这里提到的其他答案要快得多且不易出错。
| 归档时间: |
|
| 查看次数: |
4869 次 |
| 最近记录: |