是否可以在MongoDB中找到最大的文档大小?
db.collection.stats()
显示平均尺寸,这并不具有代表性,因为在我看来,尺码可能会有很大差异。
答案 0 :(得分:79)
您可以使用小型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);
答案 1 :(得分:14)
注意:这将尝试将整个结果集存储在内存中(来自.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" }
答案 2 :(得分:4)
从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 }
此:
$group
将所有项目放在一起$project
是文档$max
的{{1}} $$ROOT
代表我们得到其bsonsize的当前文档答案 3 :(得分:1)
如果你正在处理一个庞大的集合,那么将它们一次性加载到内存中是行不通的,因为你需要的RAM大于整个集合的大小才能工作。
相反,您可以使用我创建的以下包批量处理整个集合: https://www.npmjs.com/package/mongodb-largest-documents
您所要做的就是提供MongoDB连接字符串和集合名称。该脚本在完成批量遍历整个集合时将输出前X个最大的文档。
答案 4 :(得分:1)
嗯..这是一个古老的问题..但是-我想分享我的看法
我的方法-使用Mongo mapReduce
函数
首先-让我们获取每个文档的大小
db.myColection.mapReduce
(
function() { emit(this._id, Object.bsonsize(this)) }, // map the result to be an id / size pair for each document
function(key, val) { return val }, // val = document size value (single value for each document)
{
query: {}, // query all documents
out: { inline: 1 } // just return result (don't create a new collection for it)
}
)
这将返回所有文档大小,尽管值得一提的是将其保存为集合是一种更好的方法(结果是result
字段中的结果数组)
第二个-通过处理此查询来获取文档的最大大小
db.metadata.mapReduce
(
function() { emit(0, Object.bsonsize(this))}, // mapping a fake id (0) and use the document size as value
function(key, vals) { return Math.max.apply(Math, vals) }, // use Math.max function to get max value from vals (each val = document size)
{ query: {}, out: { inline: 1 } } // same as first example
)
将为您提供单个结果的值等于最大文档大小
简而言之:
您可能想使用第一个示例并将其输出保存为一个集合(将out
选项更改为所需的集合名称)并对其进行进一步的聚合(最大大小,最小大小等)。
-OR-
您可能希望使用单个查询(第二个选项)来获取单个统计信息(最小值,最大值,平均值等)
答案 5 :(得分:0)
使用aggregation framework和有关集合中文档的少量知识,查找MongoDB集合中最大的文档可能比其他答案快100倍。此外,使用其他方法(forEach
,甚至更糟,将所有文档发送到客户端),您都可以在几秒钟内得到结果,而分钟则要得到结果。
您需要知道文档中的哪个字段可能是最大的字段-您几乎总是会知道。只有两个实用的 1 MongoDB types可以具有可变大小:
聚合框架可以计算每个长度。请注意,您不会获得数组的大小(以字节为单位),但会得到元素的长度。但是,通常更重要的是哪些异常文档,而不是确切地占用了多少字节。
这是对数组进行的操作。举例来说,假设我们在一个社交网络中有一个用户集合,并且我们怀疑数组friends.ids
可能非常大(实际上,您可能应该将friendsCount
之类的单独字段与数组,但为示例起见,我们假设它不可用):
db.users.aggregate([
{ $match: {
'friends.ids': { $exists: true }
}},
{ $project: {
sizeLargestField: { $size: '$friends.ids' }
}},
{ $sort: {
sizeLargestField: -1
}},
])
关键是使用$size
aggregation pipeline operator。但是它仅适用于数组,那么文本字段呢?我们可以使用$strLenBytes
operator。假设我们怀疑bio
字段也可能很大:
db.users.aggregate([
{ $match: {
bio: { $exists: true }
}},
{ $project: {
sizeLargestField: { $strLenBytes: '$bio' }
}},
{ $sort: {
sizeLargestField: -1
}},
])
您还可以使用$size
组合$strLenBytes
和$sum
来计算多个字段的大小。在绝大多数情况下,20% of the fields will take up 80% of the size(如果不是10/90甚至不是1/99),大字段必须是字符串或数组。
1 从技术上讲,很少使用的binData
类型也可以具有可变大小。
答案 6 :(得分:0)
受Elad Nana's package的启发,但可在MongoDB控制台中使用:
function biggest(collection, limit=100, sort_delta=100) {
var documents = [];
cursor = collection.find().readPref("nearest");
while (cursor.hasNext()) {
var doc = cursor.next();
var size = Object.bsonsize(doc);
if (documents.length < limit || size > documents[limit-1].size) {
documents.push({ id: doc._id.toString(), size: size });
}
if (documents.length > (limit + sort_delta) || !cursor.hasNext()) {
documents.sort(function (first, second) {
return second.size - first.size;
});
documents = documents.slice(0, limit);
}
}
return documents;
}; biggest(db.collection)
limit
个最大文档的列表,而不仅仅是最大的limit
将输出列表排序并剪切到sort_delta
nearest
用作read preference(如果您在从属节点上,则可能还希望在连接上使用rs.slaveOk()
以便能够列出集合)答案 7 :(得分:-1)
正如 Xavier Guihot 已经提到的,Mongo 4.4 中引入了一个新的 $bsonSize 聚合运算符,它可以为您提供对象的大小(以字节为单位)。除此之外,我只想提供我自己的示例和一些统计数据。
// I had an `orders` collection in the following format
[
{
"uuid": "64178854-8c0f-4791-9e9f-8d6767849bda",
"status": "new",
...
},
{
"uuid": "5145d7f1-e54c-44d9-8c10-ca3ce6f472d6",
"status": "complete",
...
},
...
];
// and I've run the following query to get documents' size
db.getCollection("orders").aggregate(
[
{
$match: { status: "complete" } // pre-filtered only completed orders
},
{
$project: {
uuid: 1,
size: { $bsonSize: "$$ROOT" } // added object size
}
},
{
$sort: { size: -1 }
},
],
{ allowDiskUse: true } // required as I had huge amount of data
);
结果,我收到了按大小降序排列的文档列表。
对于总共约 3M 条记录和约 70GB 大小的集合,上述查询耗时约 6.5 分钟。