python - 从 GridFS 中清除孤立文件

标签 python mongodb mongodb-query gridfs

我有一个引用 GridFS 文件的集合,通常每条记录有 1-2 个文件。这些集合相当大——父集合中大约有 705k 条记录,以及 790k GridFS 文件。随着时间的推移,出现了许多孤立的 GridFS 文件——父记录被删除,但引用的文件没有。我现在正尝试从 GridFS 集合中清除孤立文件。

像建议的 here 这样的方法的问题是,将 700k 记录组合成一个大的 id 列表会导致内存中大约 4mb 的 Python 列表 - 将其传递到 Mongo 中 fs.files 集合上的 $nin 查询从字面上看永远。反过来(获取 fs.files 中所有 ID 的列表并查询父集合以查看它们是否存在)也需要很长时间。

有没有人反对这个并开发出更快的解决方案?

最佳答案

首先,让我们花点时间考虑一下 GridFS 实际上是。作为初学者,让我们阅读引用的手册页:

GridFS is a specification for storing and retrieving files that exceed the BSON-document size limit of 16MB.

因此,将其排除在外,这很可能就是您的用例。但这里要吸取的教训是GridFS不是自动存储文件的“首选”方法。

在您的案例(和其他案例)中发生的事情是因为这是“驱动程序级别”规范(而 MongoDB 本身在这里没有魔法),您的"file"已被“拆分”为两个集合。一个集合用于内容的主要引用,另一个集合用于数据“ block ”。

您(和其他人)的问题是,既然“主要”引用已被删除,您已经设法留下了“ block ”。那么在数量众多的情况下,如何摆脱孤儿。

您当前的阅读内容是“循环和比较”,并且由于 MongoDB 不执行连接,因此确实没有其他答案。但有些事情可以提供帮助。

因此与其运行巨大的 $nin,不如尝试做一些不同的事情来打破它。考虑以相反的顺序工作,例如:

db.fs.chunks.aggregate([
    { "$group": { "_id": "$files_id" } },
    { "$limit": 5000 }
])

所以你在那里做的是从所有条目中获取 distinct "files_id"值(作为对 fs.files 的引用),5000您的条目开始。然后您当然会回到循环,检查 fs.files 是否有匹配的 _id。如果未找到某些内容,则从您的“ block ”中删除与“files_id”匹配的文档。

但那只有 5000,所以保留在该集合中找到的last id,因为现在您将再次运行相同的聚合语句,但有所不同:

db.fs.chunks.aggregate([
    { "$match": { "files_id": { "$gte": last_id } } },
    { "$group": { "_id": "$files_id" } },
    { "$limit": 5000 }
])

所以这有效因为ObjectId 值是monotonic或“不断增加”。所以所有条目总是大于最后一个。然后您可以再次循环这些值,并在找不到的地方执行相同的删除操作。

这会“永远”吗?好吧是的。您可能雇用db.eval()为此,请阅读文档。但总的来说,这是您使用两个集合所付出的代价。

回到起点。 GridFS spec 是这样设计的,因为它特别想绕过 16MB 的限制。但如果那不是你的限制,那么质疑为什么你正在使用GridFS首先。

MongoDB 在给定 BSON 文档的任何元素中存储“二进制”数据没有问题。所以你不需要使用GridFS只是为了存储文件。如果您这样做了,那么您的所有更新将完全是“原子的”,因为它们只作用于一个集合中的一个文档一次。

GridFS 故意将文档拆分到集合中,如果你使用它,那么你就会忍受痛苦。因此,如果您需要就使用它,但如果您不需要,那么只需将BinData存储为普通字段,这些问题就会消失.

但至少你有一个比将所有内容都加载到内存中更好的方法。

关于python - 从 GridFS 中清除孤立文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22574178/

相关文章:

javascript - 在 mongoDB 中创建一个 firebase 样式的权限层次结构

python - 自动完成什么都不做。怎么了?

node.js - 如何使用 mongoose 聚合函数计算每个评分

java - 将 MongoClient 与列表 ServerAddress 一起使用时出现 com.mongodb.MongoTimeoutException

mongodb - Mongoose 更新: obtaining pushed subdocument's _id

java - 想要创建动态 mongo 查询来接受 DTO 字段

python - 对数似然成本函数 : mean or sum?

python - 如何在调用更新后端状态的函数时从 python (fastapi) 发送服务器端事件

python - 在 asyncio 中的 KeyboardInterrupt 之后等待任务完成

MongoDB查询找到最近两天的最大值