使用 MapReduce 的联合集 MongoDB

Union Set using MapReduce MongoDB

我正在尝试使用 MapReduce 合并两个集合。它们具有相同的结构,例如:

db.tableR.insert({product:"A", quantity:150});
db.tableR.insert({product:"B", quantity:100});
db.tableR.insert({product:"C", quantity:60});
db.tableR.insert({product:"D", quantity:200});

db.tableS.insert({product:"A", quantity:150});
db.tableS.insert({product:"B", quantity:100});
db.tableS.insert({product:"F", quantity:220});
db.tableS.insert({product:"G", quantity:130});

我希望 MapReduce 删除重复项。

我正在创建一个根据数量划分集合的地图:

map = function(){
    if (this.quantity<150){
        var key=0;
    }else{
    var key=1;
    }
    var value = {"product":this.product, "quantity":this.quantity};
    emit(key,value);
};

现在我希望 reduce 函数删除重复项,但我找不到将新的添加到 reduced var 的方法。

这是我试过的:

reduce = function(keys,values){
var reduced = {
    product:"",
    quantity:""
};
for (var i=0; i < values.length;i++)
{
    if(values[i].product !== null) {reduced.insert({product: values[i].product, quantity: values[i].quantity})}

}
return reduced;};

db.tableR.mapReduce(map,reduce,{out:'map_reduce_result'});
db.tableS.mapReduce(map,reduce,{out:'map_reduce_result'});
db.map_reduce_result.find();

我可以使用什么功能?

我的预期输出:

   {"_id" : 0, "value" : {"product" : "B","quantity" : 100}}
   {"_id" : 0, "value" : {"product" : "C","quantity" : 60}}
   {"_id" : 0, "value" : {"product" : "G","quantity" : 130}}
   {"_id" : 1, "value" : {"product" : "A","quantity" : 150}}
   {"_id" : 1, "value" : {"product" : "D","quantity" : 200}}
   {"_id" : 1, "value" : {"product" : "F","quantity" : 220}}

reduce 函数只能 return 单个值,因此您希望它对每一行都执行。 reduce 函数会为映射函数中的每个唯一键 return 调用。您的键是 0 和 1,因此每个集合只会调用两次 - 一次是键 0,一次是键 1。因此,每个集合的最大结果数仅为 2。

您需要做的是在map函数中设置产品的key:

map = function(){
    emit(this.product,{product:this.product,quantity:this.quantity});
};

现在,将为每个唯一产品值调用 reduce 函数。我们的新 map 函数只是 returns 数组中的第一个值(如果在同一个集合中有重复项,它只会取第一个。你可以在这里聪明一点,取最高或最低数量 - 或者数量等)。

reduce = function(keys,values){
    return values[0];
};

运行 你的第一个 map reduce 作业:

db.tableR.mapReduce(map,reduce,{out:'map_reduce_result'});

运行 你的第二个,但这次 merge 结果:

db.tableS.mapReduce(map,reduce,{out: {merge: 'map_reduce_result'}});

现在db.map_reduce_result.find()returns:

{ "_id" : "A", "value" : { "product" : "A", "quantity" : 150 } }
{ "_id" : "B", "value" : { "product" : "B", "quantity" : 100 } }
{ "_id" : "C", "value" : { "product" : "C", "quantity" : 60 } }
{ "_id" : "D", "value" : { "product" : "D", "quantity" : 200 } }
{ "_id" : "F", "value" : { "product" : "F", "quantity" : 220 } }
{ "_id" : "G", "value" : { "product" : "G", "quantity" : 130 } }

显然 _id 与您要查找的内容不匹配。如果你绝对需要,你可以像这样使用聚合框架:

db.map_reduce_result.aggregate([{$project:{
  _id:{$cond: { if: { $gte: [ "$value.quantity", 150 ] }, then: 1, else: 0 }},
  value:1
}}]);

这导致:

{ "_id" : 1, "value" : { "product" : "A", "quantity" : 150 } }
{ "_id" : 0, "value" : { "product" : "B", "quantity" : 100 } }
{ "_id" : 0, "value" : { "product" : "C", "quantity" : 60 } }
{ "_id" : 1, "value" : { "product" : "D", "quantity" : 200 } }
{ "_id" : 1, "value" : { "product" : "F", "quantity" : 220 } }
{ "_id" : 0, "value" : { "product" : "G", "quantity" : 130 } }

注意:如果来自不同集合的两行具有相同的产品 ID,但数量不同,我不确定哪一个将被 returned。