我在MongoDB中有数据。一个对象的结构如下:
{
"_id" : ObjectId("5395177980a6b1ccf916312c"),
"institutionId" : "831",
"currentObject" : {
"systemIdentifiers" : [
{
"value" : "24387",
"system" : "ABC"
}]
}
}
我必须知道有多少个对象具有相同的 institutionId 和 systemIdentifiers [0] .value ,并且只想返回以这种方式重复的对象。 为此,我将这些ID分组并计算出现次数。
当 count 大于1时,应返回对象(一对ID)。
这是一块使用MapReduce进行分组的代码。
var map = function() {
var key = this.institutionId;
var val = this.currentObject.systemIdentifiers[0].value;
emit({"institutionId":key,"workId":val}, {count:1});
};
var reduce = function(key, values) {
var count = 0;
values.forEach(function(v) {
count += v['count'];
});
return {count: count};
}
db.name.mapReduce(map, reduce, {out: "grouped"})
db.grouped.find()
为了只获得数量大于1的人,我做
db.grouped.aggregate([{$match:{"value.count":{$gt: 1}}}])
然后是
后面的示例结果{
"_id" : {
"institutionId" : "1004",
"workId" : "591426"
},
"value" : {
"count" : 2
}
}
但我很好奇是否可以通过将MapReduce作为一个语句来完成它。就像添加终结者一样。
答案 0 :(得分:2)
如果有一个文件有一个密钥,那么永远不会进入reduce ,被认为已经减少了,那就是MongoDB map-reduce的行为:
MongoDB will not call the reduce function for a key that has only a single value.
使用finalzie也没有多大帮助,即如果在最终功能中你执行了BaseMenuModel
,那么结果中你将获得None(而不是1)。
我担心使用(一个)map-reduce,结果中的计数为1的文档将 alwasy ,因为它们是从地图中启动的。
您可以在链中使用2个地图缩小操作,在第二个地图中,您不会发出具有计数的文档<但是这些并不认为它比你的例子中的额外查询更好。
答案 1 :(得分:1)
更好,更简单,更有效的方法是使用聚合框架,您可以使用 $arrayElemAt
等运算符从数组返回第一个子文档,然后使用<强> $group
管道来汇总计数。然后,您可以放置 $match
管道,根据给定的条件过滤结果。
以下示例显示了这种更快的方法:
db.name.aggregate([
{
"$project": {
"key": "$institutionId",
"val": {
"$arrayElemAt": ["$currentObject.systemIdentifiers", 0]
}
}
},
{
"$group": {
"_id": {
"institutionId": "$key",
"workId": "$val.value"
},
"count": { "$sum": 1 }
}
},
{ "$match": { "count": { "$gt": 1 } } }
])