MongoDB正在删除fs.chunks中不在fs.files中的位置



我在fs.chunks中有10 GB的数据,我想删除所有不在fs.files上的文档。我已经删除了fs.file中我不想要的每个条目,所以fs.filees中的每个id都是我想保留的文件。

因此,我想要类似db.fs.chunks.remove({"_id": {$nin: fs.files._id}})或"删除fs.chunks中不存在于fs.files中的所有条目"的东西。

编辑:我正在寻找与SQL delete from fs_chunks where id not in (select id from fs_files)等效的mongo。

我认为除了执行查找然后使用forEach迭代之外,没有简单的方法可以做到这一点。所以类似于:

function removeChunkIfNoOwner(chunk){
  //Look for the parent file
  var parentCount = db.fs.files.find({'_id' : chunk.files_id}).count();
  if (parentCount === 0 ){
     db.fs.chunks.remove({'_id': chunk._id});
     print("Removing chunk " + chunk._id);
  }
}
db.fs.chunks.find().forEach(removeChunkIfNoOwner);

你可以看到,如果你创建这样一个函数,这种方法应该有效:

function listParentFile(chunk){
   var parent = db.fs.files.findOne({'_id' : chunk.files_id});
   printjson(parent);
}
db.fs.chunks.find().forEach(listParentFile);

我发现这个基于Mick的解决方案可以更快地处理大量块:

function removeChunkIfNoOwner(files_id){
  //Look for the parent file
  var parentCount = db.fs.files.find({'_id' : files_id}).count();
  if (parentCount === 0 ){
      res = db.fs.chunks.remove({'files_id':files_id})
  }
}
files = db.fs.chunks.distinct('files_id').forEach(removeChunkIfNoOwner)

使用distinct对我不起作用,因为我的集合太大了。对Bas的查询进行了轻微的修改,对我有效。

function removeChunkIfNoOwner(chunk){
  var parentCount = db.fs.files.find({'_id' : chunk.files_id}).count();
  if(parentCount === 0){
    res = db.fs.chunks.remove({'files_id':chunk._id})
    print("item removed")
  }
}
files = db.fs.chunks.find({files_id:{$exists:1}},{data:0}).forEach(removeChunkIfNoOwner)

我发现这个解决方案与其他提出的解决方案相比运行得非常快

https://gist.github.com/xelaz/8aceeacc6306c5dd92f2c91699d89a27

db.getCollection('fs.chunks').aggregate([{
    $lookup: {
      from: 'fs.files',
      localField: 'files_id',
      foreignField: '_id',
      as: 'file'
    }
  },
  {
    $unwind: {
      path: '$file',
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $match: {
      file: {
        $exists: false
      }
    }
  },
  {
    $project: {
      _id: 1,
      files_id: 1
    }
  },
])toArray().forEach(function(chunk) {
  printjson(chunk);
  // db.getCollection('fs.chunks').remove({ _id: chunk._id });
});

所有给定的解决方案都可以工作,但由于每个块都要删除db.getCollection('fs.chunks').remove(...),因此可能需要很长时间才能处理许多受影响的块。以下是一种通过一个删除查询删除所有受影响的块的方法:

let chunksCollection = "fs.chunks";
let filesCollection = "fs.files";
let unrelatedChunks =
    db.getCollection(chunksCollection).aggregate(
        [
            {
                // Join with related files documents
                $lookup: {
                    from: filesCollection,
                    localField: "files_id",
                    foreignField: "_id",
                    as: "files",
                },
            },
            {
                // Filter chunks without related files document
                $match: {
                    files: {
                        $size: 0,
                    },
                },
            },
            {
                // Project files_id
                $project: {
                    files_id: "$files_id",
                },
            },
        ]
    )
        .toArray();
// Create an array with files_id
let files_id_OfUnrelatedChunks = unrelatedChunks.map(document => document.files_id)
// Delete all chunks with no longer existing files_id
db.getCollection(chunksCollection).deleteMany({"files_id": {$in: files_id_OfUnrelatedChunks}})

最新更新