MongoDB MapReduce,当计数> 1时才返回

3

我有一些MongoDB中的数据,其中一个对象的结构如下:

{
    "_id" : ObjectId("5395177980a6b1ccf916312c"),
    "institutionId" : "831",
    "currentObject" : {
          "systemIdentifiers" : [
            {
                "value" : "24387",
                "system" : "ABC"
            }]
      }
}

我需要知道有多少个对象拥有相同的institutionIdsystemIdentifiers [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语句就完成。例如添加一个finalizer之类的东西。

2个回答

2
如果有一个关键字的单个文档,它将永远不会进入reduce,因为已经被视为已经减少了,这是MongoDB映射减少的行为。即使使用finalize也无济于事,即使在finalize函数中执行if count>1 then return reducedVal else None,结果中也会出现None(而不是1)。恐怕使用一个map-reduce时,计数为1的文档将始终在结果中,因为它们从map中启动。您可以在链中使用2个map reduce操作,在第二个map中,您不会发出计数小于2的文档。但是这并不比在您的示例中使用额外查询更好。

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 } } }
])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接