我在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}})