我已经阅读了几篇文章和示例,并且尚未找到在MongoDB中执行此SQL查询的有效方法(其中有数百万个行文档)
首次尝试
(例如,从这个几乎重复的问题 - Mongo equivalent of SQL's 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
第三次尝试
我还没有尝试,但有一些涉及mapReduce
e.g。
同时
似乎GitHub上有一个拉取请求修复.distinct
方法,提到它只应返回一个计数,但它仍然打开:https://github.com/mongodb/mongo/pull/34
但此时此刻我觉得值得问一下,这个主题的最新消息是什么?我是否应该转移到SQL或其他NoSQL DB以获取不同的计数?还是有效率的方法?
更新:
对MongoDB官方文档的评论并不令人鼓舞,这是否准确?
http://www.mongodb.org/display/DOCS/Aggregation#comment-430445808
UPDATE2:
似乎新的聚合框架回答了上述评论...(MongoDB 2.1 / 2.2及更高版本,开发预览可用,不适用于制作)
答案 0 :(得分:73)
1)最简单的方法是通过聚合框架。这需要两个“$ group”命令:第一个按不同的值分组,第二个命令计算所有不同的值
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做到这一点,你可以。这也是一个两阶段的过程:在第一阶段,我们构建一个新的集合,其中包含密钥的每个不同值的列表。在第二个中,我们对新集合执行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()的返回值中获取结果数。
答案 1 :(得分:37)
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;
答案 2 :(得分:3)
以下解决方案为我工作
db.test.distinct( '用户'); [“alex”,“England”,“France”,“Australia”]
db.countries.distinct( '国家')。长度 4