在索引列上的MongoDB select count(distinct x) – 计算大数据集的唯一结果

我已经经历了几篇文章和示例,并且还没有find一种有效的方法来在MongoDB中进行这种SQL查询(其中有数百万 文件)

第一次尝试

(例如,从这个几乎重复的问题 – Mongo相当于SQL的SELECT DISTINCT? )

db.myCollection.distinct("myIndexedNonUniqueField").length 

显然我得到这个错误,因为我的数据集是巨大的

 Thu Aug 02 12:55:24 uncaught exception: distinct failed: { "errmsg" : "exception: distinct too big, 16mb cap", "code" : 10044, "ok" : 0 } 

第二次尝试

我决定尝试做一个小组

 db.myCollection.group({key: {myIndexedNonUniqueField: 1}, initial: {count: 0}, reduce: function (obj, prev) { prev.count++;} } ); 

但是我得到了这个错误信息:

 exception: group() can't handle more than 20000 unique keys 

第三次尝试

我还没有尝试过,但有几个build议涉及到mapReduce

例如

  • 这个如何在MongoDB中做出截然不同的分组? (不接受,回答作者/ OP没有testing)
  • 这个由function组成的MongoDB组 (类似于第二次尝试)
  • 这一个http://blog.emmettshear.com/post/2010/02/12/Counting-Uni​​ques-With-MongoDB
  • 这一个https://groups.google.com/forum/?fromgroups#!topic/mongodb-user/trDn3jJjqtE
  • 这一个http://cookbook.mongodb.org/patterns/unique_items_map_reduce/

似乎GitHub上有一个pull请求修复.distinct方法提到它应该只返回一个计数,但它仍然是开放的: https : //github.com/mongodb/mongo/pull/34

但在这一点上,我认为值得在这里问一下,关于这个问题最新的是什么? 我应该迁移到SQL还是另一个NoSQL数据库来区分不同的计数? 还是有一个有效的方法?

更新:

对MongoDB官方文档的评论并不令人鼓舞,这是否准确?

http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808

UPDATE2:

似乎新的聚合框架回答上述评论…(MongoDB 2.1 / 2.2及以上,开发预览可用,不生产)

http://docs.mongodb.org/manual/applications/aggregation/

1)最简单的方法是通过聚合框架。 这需要两个“$组”命令:第一个按不同的值分组,第二个按照所有不同的值进行计数

 pipeline = [ { $group: { _id: "$myIndexedNonUniqueField"} }, { $group: { _id: 1, count: { $sum: 1 } } } ]; // // Run the aggregation command // R = db.runCommand( { "aggregate": "myCollection" , "pipeline": pipeline } ); printjson(R); 

2)如果你想用Map / Reduce做到这一点,你可以。 这也是一个两阶段的过程:第一阶段,我们build立一个新的集合,列出关键的每个不同的价值。 在第二个我们对新的集合做一个count()。

 var SOURCE = db.myCollection; var DEST = db.distinct DEST.drop(); map = function() { emit( this.myIndexedNonUniqueField , {count: 1}); } reduce = function(key, values) { var count = 0; values.forEach(function(v) { count += v['count']; // count each distinct value for lagniappe }); return {count: count}; }; // // run map/reduce // res = SOURCE.mapReduce( map, reduce, { out: 'distinct', verbose: true } ); print( "distinct count= " + res.counts.output ); print( "distinct count=", DEST.count() ); 

请注意,不能返回map / reduce内联的结果,因为这可能会超出16MB的文档大小限制。 您可以将计算保存到集合中,然后count()集合的大小,或者可以从mapReduce()的返回值中获取结果的数量。

 db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}}); 

直接导致:

 db.myCollection.aggregate( {$group : {_id : "$myIndexedNonUniqueField"} }, {$group: {_id:1, count: {$sum : 1 }}}) .result[0].count; 

以下解决scheme为我工作

db.test.distinct( '用户'); [“alex”,“英国”,“法国”,“澳大利亚”]

db.countries.distinct('country')。length 4