【问题标题】:Mongoose mapReduce : reduce returns object or array?Mongoose mapReduce:reduce 返回对象还是数组?
【发布时间】:2014-07-09 12:51:48
【问题描述】:

我有以下收藏:

/* 0 */
{
    "clientID" : ObjectId("51b9c10d91d1a3a52b0000b8"),
    "_id" : ObjectId("532b4f1cb3d2eacb1300002b"),
    "answers" : [],
    "questions" : []
}

/* 1 */
{
    "clientID" : ObjectId("51b9c10d91d1a3a52b0000b8"),
    "_id" : ObjectId("532b6b9eb3d2eacb1300002c"),
    "answers" : [ 
        "1", 
        "8"
    ],
    "questions" : [ 
        "1", 
        "2", 
        "3"
    ]
}

/* 2 */
{
    "clientID" : ObjectId("51b9c10d91d1a3a52b0000b8"),
    "_id" : ObjectId("532b6baeb3d2eacb1300002d"),
    "answers" : [ 
        "1", 
        "8"
    ],
    "questions" : [ 
        "1", 
        "2", 
        "3"
    ]
}

/* 3 */
{
    "clientID" : ObjectId("5335f9d864e2b1290c00012e"),
    "_id" : ObjectId("533b828146ca43634000002d"),
    "answers" : [ 
        "ORANGE"
    ],
    "questions" : [ 
        "Color"
    ]
}

/* 4 */
{
    "clientID" : ObjectId("5335f9d864e2b1290c00012e"),
    "_id" : ObjectId("5351be327b539a4d1a00002b"),
    "answers" : [ 
        "ORANGE"
    ],
    "questions" : [ 
        "Color"
    ]
}

/* 5 */
{
    "clientID" : ObjectId("5335f9d864e2b1290c00012e"),
    "_id" : ObjectId("5351be5ec89d717d1a00002b"),
    "answers" : [ 
        "ORANGE"
    ],
    "questions" : [ 
        "Color"
    ]
}

我正在运行以下代码以查找(问题、答案)组合在集合中出现的次数:

o.map= function(){ 
    emit({"questions" : this.questions, "answers" :this.answers },this.clientID) 
};

o.reduce = function(answers, collection){
    return collection.length; 
};

logSearchDB.mapReduce(o,function (err, results) {
    results.sort(function(a, b){return b.value-a.value});
    for (var i = 0; i < results.length; i++) {
        console.log(JSON.stringify(results[i]))
    };

})

输出是:

{"_id":{"questions":[],"answers":[]},"value":"51b9c10d91d1a3a52b0000b8"}
{"_id":{"questions":["Color"],"answers":["ORANGE"]},"value":3}
{"_id":{"questions":["1","2","3"],"answers":["1","8"]},"value":2}

我预计第一行会有“价值”:1

我猜'reduce'函数得到了一个'collection'对象:“51b9c10d91d1a3a52b0000b8”,而不是得到一个数组:[“51b9c10d91d1a3a52b0000b8”]。

为什么 map reduce 不将所有内容收集到一个数组中?

【问题讨论】:

    标签: node.js mongodb mapreduce mongoose aggregation-framework


    【解决方案1】:

    您在第一行中只有一个普通值的原因是您的 key 值只出现了 一次。这通常是 mapReduce 的工作方式,至少在原始论文中指定的方式是这样。

    所以当只有一个键时,reduce 函数实际上并没有被调用。要解决此问题,您可以在 map reduce 中使用 finalize 函数:

    var finalize = function(key,value) {
        if ( typeof(value) != "number" )
            value = 1;
    
        return value;
    };
    
    db.collection.mapReduce(
        mapper,
        reducer,
        { 
          "finalize": finalize,
          "out": { "inline": 1 }
        }
    );
    

    这会遍历所有输出,并看到当该值被视为不是数字时,即您正在发出的 clientID,那么该值设置为 1,因为这就是 hany 在分组。

    确实,您的查询比 mapReduce 更适合 aggregation framework。聚合框架是本机代码实现,而不是使用 JavaScript 解释器。它的运行速度比 mapReduce 快得多:

    db.collection.aggregate([
        { "$group": {
            "_id": {
                "questions": "$questions",
                "answers": "$answers"
            },
            "count": { "$sum": 1 }
        }}
    ])
    

    所以它是更好的选择。这是对 MongoDB 的较晚介绍,因此人们仍然倾向于从 mapReduce 的角度进行思考,否则存在早期版本的 MongoDB 的遗留代码。但这已经存在了很长一段时间了。

    另请参阅聚合框架的operator reference

    【讨论】:

      猜你喜欢
      • 2014-03-24
      • 2020-09-14
      • 2020-11-11
      • 2017-10-26
      • 2021-10-20
      • 1970-01-01
      • 2017-04-17
      • 2016-07-28
      • 2021-12-02
      相关资源
      最近更新 更多