在MongoDB中查找最大的文档大小

sas*_*llo 47 mongodb

是否有可能在MongoDB中找到最大的文档大小?

db.collection.stats() 显示平均大小,这不是真正的代表性,因为在我的情况下,大小可能有很大差异.

Abh*_*mar 82

您可以使用小型shell脚本来获取此值.

注意:以下将进行全表扫描

let max = 0, id = null;
db.test.find().forEach(doc => {
    const size = Object.bsonsize(doc); 
    if(size > max) {
        max = size;
        id = doc._id;
    } 
});
print(id, max);
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法不将每个文档加载到客户端来计算其大小?也许以某种方式使用聚合. (5认同)
  • 我假设这个大小以字节为单位? (2认同)

Mik*_*raf 18

注意:这将尝试将整个结果集存储在内存中(从.toArray).小心大数据集.不要在生产中使用!Abishek的答案具有处理游标而不是内存数组的优势.

如果你也想要_id,试试这个.给定一个名为"请求"的集合:

// Creates a sorted list, then takes the max
db.requests.find().toArray().map(function(request) { return {size:Object.bsonsize(request), _id:request._id}; }).sort(function(a, b) { return a.size-b.size; }).pop();

// { "size" : 3333, "_id" : "someUniqueIdHere" }
Run Code Online (Sandbox Code Playgroud)

  • 这应该不是公认的答案。在大型集合上调用`toArray()`可能会使客户端崩溃。您不能将10 TB的数据拉入客户端的内存,然后尝试对其进行“映射”。您需要对其进行迭代,并让驱动程序处理批处理。 (2认同)
  • @PeteGarafano它在回答中相当清楚地说,它将把所有内容都存储到内存中,而不是用于生产。不要对我投反对票,因为您复制并粘贴到了产品中。 (2认同)

Dan*_*scu 14

在 MongoDB 集合中查找最大的文档可以比使用聚合框架和有关集合中文档的一点点知识的其他答案快约 100 倍。此外,您将在几秒钟内获得结果,而使用其他方法(forEach或更糟,将所有文档发送给客户端)则需要几分钟。

您需要知道文档中的哪些字段可能是最大的 -您几乎总是会知道的。只有两种实用的1 MongoDB类型可以具有可变大小:

  • 数组
  • 字符串

聚合框架可以计算每个的长度。请注意,您不会获得数组的字节大小,而是元素的长度。然而,更重要的是离群文档是哪些,而不是它们占用了多少字节。

以下是对数组的处理方式。举个例子,假设我们有一个社交网络中的用户集合,我们怀疑这个数组friends.ids可能非常大(实际上你应该保持一个单独的字段,比如friendsCount与数组同步,但为了举例,我们' 会假设那不可用):

db.users.aggregate([
    { $match: {
        'friends.ids': { $exists: true }
    }},
    { $project: { 
        sizeLargestField: { $size: '$friends.ids' } 
    }},
    { $sort: {
        sizeLargestField: -1
    }},
])
Run Code Online (Sandbox Code Playgroud)

关键是使用$size聚合管道运算符。不过它只适用于数组,那么文本字段呢?我们可以使用$strLenBytes运算符。假设我们怀疑该bio字段也可能非常大:

db.users.aggregate([
    { $match: {
        bio: { $exists: true }
    }},
    { $project: { 
        sizeLargestField: { $strLenBytes: '$bio' } 
    }},
    { $sort: {
        sizeLargestField: -1
    }},
])
Run Code Online (Sandbox Code Playgroud)

您也可以组合$size$strLenBytes使用$sum计算多个字段的大小。在绝大多数情况下,20% 的字段将占据 80% 的大小(如果不是 10/90 甚至 1/99),并且大字段必须是字符串或数组。


1从技术上讲,很少使用的binData类型也可以具有可变大小。

  • @Sammaye 接受的答案中的代码由客户端 shell 执行,而不是由数据库服务器执行。因此,它使用游标将每个文档一一加载到客户端,计算其大小,并确定最大的文档。是的,它不会将完整的集合存储在客户端的内存中,但它仍然需要通过网络传输数据。所以这种方法对于大型集合并不是很有用。 (3认同)

Xav*_*hot 10

开始Mongo 4.4,新的聚合运算符$bsonSize在编码为 BSON 时返回给定文档的大小(以字节为单位)。

因此,为了找到最大的文档的bson大小:

// { "_id" : ObjectId("5e6abb2893c609b43d95a985"), "a" : 1, "b" : "hello" }
// { "_id" : ObjectId("5e6abb2893c609b43d95a986"), "c" : 1000, "a" : "world" }
// { "_id" : ObjectId("5e6abb2893c609b43d95a987"), "d" : 2 }
db.collection.aggregate([
  { $group: {
    _id: null,
    max: { $max: { $bsonSize: "$$ROOT" } }
  }}
])
// { "_id" : null, "max" : 46 }
Run Code Online (Sandbox Code Playgroud)

这个:

  • $group将所有项目放在一起
  • $projects 的$max文件'$bsonSize
  • $$ROOT 表示我们获得 bsonsize 的当前文档

  • 截至 2022 年,这比公认的答案更好。 (2认同)
  • 如何提取文档 ID? (2认同)