【问题标题】:MongoDB MapReduce, return only when count > 1MongoDB MapReduce,仅在 count > 1 时返回
【发布时间】:2017-04-15 23:24:46
【问题描述】:

我在 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 左右。

【问题讨论】:

    标签: javascript mongodb mapreduce mongodb-query aggregation-framework


    【解决方案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 } } }
    ])
    

    【讨论】:

      【解决方案2】:

      如果有一个文档有一个键,它将永远不会进入reduce,被认为已经减少了,这就是MongoDB map-reduce的行为:

      MongoDB will not call the reduce function for a key that has only a single value.

      使用 finalzie 也无济于事,即如果在 finalize 函数中执行 if count > 1 then return reducedVal else None,那么结果中将有 None(而不是 1)。

      我担心使用(一个)map-reduce,计数为 1 的文档将总是在结果中,因为它们是从 map 中触发的。

      您可以在一个链中使用 2 个 map reduce 操作,在第二个 map 中,您不会发出 count

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-11
        • 1970-01-01
        • 2011-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多