MongoDB - 筛选和统计大型集合以进行统计

MongoDB - Filter and count large collections for statistics

我在 Rails 中使用 Mongoid。我有一个名为 "datasets" 的集合,其中包含大约 600,000 个文档。在每个数据集中,都有一个可能存在也可能不存在的键 "files"。在文件内部有一个对象(文件)数组。我需要获取所有包含文件的数据集,然后计算这些数据集上的所有文件。这就是我所拥有的,但它抛出一个错误,说它超过了最大文档大小:

total = Dataset.collection.aggregate([
  { '$project' => { files: 1 }},
  { '$unwind' => '$files' },
  { '$group' => {_id: "$_id", count: {'$sum' => 1} } }
])

我可以使用以下方法让它工作,但它太慢了,根本没有真正使用数据库的强大功能:

datasets_with_files = Dataset.where(:files.exists => true)

count = 0
datasets_with_files.each do |dataset|
  count += dataset.files.count
end

count

所以基本上我需要知道 A. 执行此操作的最佳查询类型是什么,以及 B. 如果聚合是最好的方法,如何处理超过最大大小的文档以便我可以执行类似的查询这个。

解决方案:

我在不需要游标或磁盘使用的情况下完成了这项工作:

Dataset.collection.aggregate([
  { '$match' => { files: { '$exists' => true }}},
  { '$unwind' => '$files' },
  { '$group' => { _id: nil, total_files: { '$sum' => 1 }}}
])[0]['total_files']

您可以使用 $size 直接投影数组字段的大小,因此在 shell 中您可以这样做:

db.test.aggregate([
    {$match: {files: {$exists: true}}},
    {$project: {count: {$size: '$files'}}}
])

在 Ruby 中看起来像:

@coll.aggregate([
  { '$match' => { files: { '$exists' => true } } },
  { '$project' => { count: { '$size' => '$files' } } }
])

包括 cursor 选项以克服结果的 16MB 大小限制:

@coll.aggregate([
  { '$match' => { files: { '$exists' => true } } },
  { '$project' => { count: { '$size' => '$files' } } }
], cursor: {})