如何在MongoDB中删除filestorage.files及对应chunks集合文档?
问题描述
已实现通过查询条件删除filestorage.files集合中的指定文件,但需要基于files_id删除filestorage.chunks集合中的对应分片数据,纠结应采用聚合还是循环机制。
集合数据示例
filestorage.files集合
[ { "_id": { "$oid": "635a68aa0651c2d869fc3fd3" }, "length": 878669, "chunkSize": 261120, "uploadDate": { "$date": { "$numberLong": "1666869418612" } }, "filename": "pexels-lucie-liz-3165335_2022-10-27T11-16-58.jpg", "contentType": "image/jpeg", "metadata": { "originalname": "pexels-lucie-liz-3165335.jpg", "parentFolder": { "$oid": "636cd238692344da47f3e301" }, "path": "files/Folder1/Folder3/pexels-lucie-liz-3165335_2022-10-27T11-16-58.jpg" } }, { "_id": { "$oid": "635a68aa0651c2d869fc3fd4" }, "length": 878669, "chunkSize": 261120, "uploadDate": { "$date": { "$numberLong": "1666869418612" } }, "filename": "nature-3165335_2022-10-27T11-16-58.jpg", "contentType": "image/jpeg", "metadata": { "originalname": "nature-3165335.jpg", "parentFolder": { "$oid": "636cd238692344da47f3e301" }, "path": "files/Folder1/Folder3/nature-3165335_2022-10-27T11-16-58.jpg" } } ]
filestorage.chunks集合
[ { "_id": { "$oid": "635a68aa0651c2d869fc3fe6" }, "files_id": { "$oid": "635a68aa0651c2d869fc3fd3" }, "n": 0, "data": { "$binary": { "base64" : "xyz", "subType": "00" } } }, { "_id": { "$oid": "635a68aa0651c2d869fc3fd5" }, "files_id": { "$oid": "635a68aa0651c2d869fc3fd3" }, "n": 0, "data": { "$binary": { "base64" : "abcd", "subType": "00" } } } ]
已尝试的代码
delete_folder_files: async (ctx:any) => { // 已实现删除指定文件,但不知道如何关联chunks集合并基于files_id删除分片数据 await FileStorage.deleteMany({'metadata.parentFolder': ctx.params.id}); await FileChunk.deleteMany({files_id : ? }) ctx.status = HttpStatusCode.OK; }
解决方案
方案1:先查询待删除文件ID,再批量删除分片(推荐)
逻辑直观易维护,适合绝大多数场景:
- 先查询出目标文件夹下所有文件的ID
- 用ID列表批量删除
filestorage.chunks中对应的数据 - 最后删除
filestorage.files中的文件
修改后的代码:
delete_folder_files: async (ctx:any) => { // 查询要删除的文件ID列表 const targetFiles = await FileStorage.find( {'metadata.parentFolder': ctx.params.id}, {_id: 1} ); const fileIds = targetFiles.map(file => file._id); // 批量删除对应分片数据(避免空查询) if (fileIds.length > 0) { await FileChunk.deleteMany({files_id: {$in: fileIds}}); await FileStorage.deleteMany({'metadata.parentFolder': ctx.params.id}); } ctx.status = HttpStatusCode.OK; }
方案2:聚合管道+删除(适合超大数据量)
如果处理百万级以上的超大文件集合,可通过MongoDB聚合管道直接在数据库层面关联删除(需MongoDB 4.2+支持),减少客户端与数据库的交互次数,但代码复杂度较高:
delete_folder_files: async (ctx:any) => { // 用聚合获取待删除的files_id,再执行删除 await FileChunk.deleteMany({ $expr: { $in: [ "$files_id", { $lookup: { from: "filestorage.files", localField: "files_id", foreignField: "_id", pipeline: [ { $match: {'metadata.parentFolder': ctx.params.id} }, { $project: { _id: 1 } } ], as: "matchedFiles" } }, "$matchedFiles._id" ] } }); await FileStorage.deleteMany({'metadata.parentFolder': ctx.params.id}); ctx.status = HttpStatusCode.OK; }
方案对比
- 方案1:代码易读、易维护,仅多一次ID查询操作,性能开销可忽略,适合90%以上的业务场景。
- 方案2:减少客户端数据传输,但聚合逻辑复杂,排查问题难度大,仅推荐超大数据量场景使用。
内容的提问来源于stack exchange,提问作者Neha
相关产品推荐
相关产品推荐

