【问题标题】:How to Group mongodb - mapReduce output?如何分组 mongodb - mapReduce 输出?
【发布时间】:2016-05-27 08:34:54
【问题描述】:

我有一个关于 mongodb 中的 mapReduce 框架的查询,所以我有一个来自 mapReduce 函数的键值对的结果,现在我想在这个 mapReduce 的输出上运行查询。

所以我正在使用 mapReduce 来找出像这样的用户的统计信息

db.order.mapReduce(function() { emit (this.customer,{count:1,orderDate:this.orderDate.interval_start}) },
function(key,values){ 
    var sum =0 ; var lastOrderDate;  
    values.forEach(function(value) {
     if(value['orderDate']){ 
        lastOrderDate=value['orderDate'];
    }  
    sum+=value['count'];
}); 
    return {count:sum,lastOrderDate:lastOrderDate}; 
},
{ query:{status:"DELIVERED"},out:"order_total"}).find()

给我这样的输出

{ "_id" : ObjectId("5443765ae4b05294c8944d5b"), "value" : { "count" : 1, "orderDate" : ISODate("2014-10-18T18:30:00Z") } }
{ "_id" : ObjectId("54561911e4b07a0a501276af"), "value" : { "count" : 2, "lastOrderDate" : ISODate("2015-03-14T18:30:00Z") } }
{ "_id" : ObjectId("54561b9ce4b07a0a501276b1"), "value" : { "count" : 1, "orderDate" : ISODate("2014-11-01T18:30:00Z") } }
{ "_id" : ObjectId("5458712ee4b07a0a501276c2"), "value" : { "count" : 2, "lastOrderDate" : ISODate("2014-11-03T18:30:00Z") } }
{ "_id" : ObjectId("545f64e7e4b07a0a501276db"), "value" : { "count" : 15, "lastOrderDate" : ISODate("2015-06-04T18:30:00Z") } }
{ "_id" : ObjectId("54690771e4b0070527c657ed"), "value" : { "count" : 6, "lastOrderDate" : ISODate("2015-06-03T18:30:00Z") } }
{ "_id" : ObjectId("54696c64e4b07f3c07010b4a"), "value" : { "count" : 1, "orderDate" : ISODate("2014-11-18T18:30:00Z") } }
{ "_id" : ObjectId("546980d1e4b07f3c07010b4d"), "value" : { "count" : 4, "lastOrderDate" : ISODate("2015-03-24T18:30:00Z") } }
{ "_id" : ObjectId("54699ac4e4b07f3c07010b51"), "value" : { "count" : 30, "lastOrderDate" : ISODate("2015-05-23T18:30:00Z") } }
{ "_id" : ObjectId("54699d0be4b07f3c07010b55"), "value" : { "count" : 1, "orderDate" : ISODate("2014-11-16T18:30:00Z") } }
{ "_id" : ObjectId("5469a1dce4b07f3c07010b59"), "value" : { "count" : 2, "lastOrderDate" : ISODate("2015-04-29T18:30:00Z") } }
{ "_id" : ObjectId("5469a96ce4b07f3c07010b5e"), "value" : { "count" : 1, "orderDate" : ISODate("2014-11-16T18:30:00Z") } }
{ "_id" : ObjectId("5469c1ece4b07f3c07010b64"), "value" : { "count" : 9, "lastOrderDate" : ISODate("2015-04-15T18:30:00Z") } }
{ "_id" : ObjectId("5469f422e4b0ce7d5ee021ad"), "value" : { "count" : 5, "lastOrderDate" : ISODate("2015-06-01T18:30:00Z") } }
......

现在我想根据不同类别的计数运行查询并对用户进行分组,例如一组计数小于 5 的用户,另一组计数小于 5-10 的用户,等等

想要输出这样的东西

{userLessThan5: 9 }
{user5to10: 2 }
{user10to15: 1 }
{user15to20: 0 }
  ....

【问题讨论】:

    标签: mongodb hadoop mapreduce mongodb-query


    【解决方案1】:

    试试这个,

    db.order.mapReduce(function() { emit (this.customer,{count:1,orderDate:this.orderDate.interval_start}) },
    function(key,values){ 
    var category; // add this new field
    var sum =0 ; var lastOrderDate;  
    values.forEach(function(value) {
     if(value['orderDate']){ 
        lastOrderDate=value['orderDate'];
    }  
    sum+=value['count'];
    }); 
    // at this point you are already aware in which category your records lies , just add a new field to mark it
     if(sum < 5){ category: userLessThan5};
     if(sum >= 5 && sum <=10){ category: user5to10};
     if(sum <= 10 && sum >= 15){ category: user10to15};
     if(sum <= 15 && sum >=20){ category: user15to20};
      ....
    return {count:sum,lastOrderDate:lastOrderDate,category:category}; 
    },
    { query:{status:"DELIVERED"},out:"order_total"}).find()
     db.order_total.aggregate([{ $group: { "_id": "$value.category", "users": { $sum: 1 } } }]);
    

    你会得到你想要的结果

    {userLessThan5: 9 }
    {user5to10: 2 }
    {user10to15: 1 }
    {user15to20: 0 }
     ....
    

    【讨论】:

      【解决方案2】:

      据我所知,我在聚合中使用您的数据编写了一个查询,可能有更好的方法来解决这个问题。

      var a=db.test.aggregate([{$match:{"value.count":{$lt:5}}},
                    { $group: { _id:"$value.count",total:{"$sum":1}}},
                   {$group:{_id:"less than 5",total:{$sum:"$total"}}}])              
      
      var b=db.test.aggregate([{$match:{"value.count":{$lt:10,$gt:5}}},
                  { $group: { _id:"$value.count",total:{"$sum":1}}},
                  {$group:{_id:"between 5 and 10",total:{$sum:"$total"}}}])
      
      var c=db.test.aggregate([{$match:{"value.count":{$lt:15,$gt:10}}},
             { $group: { _id:"$value.count",total:{"$sum":1}}},
             {$group:{_id:"between 10 and 15",total:{$sum:"$total"}}}])
      

      将a、b、c插入另一个集合

      【讨论】:

      • 实际上您的解决方案建议首先我需要在测试集合中插入数据,查询也仅限于我显示的示例数据,但实际上我希望所有这些类别都有 5 个记录间隔。
      • 我已经拿了一些测试集合进行测试,用你的“order_total”集合替换它。我也会看看是否有更好的方法来解决这个问题。
      【解决方案3】:

      您可以尝试通过aggregate 将 mapreduce 后的输出数据分组为每 5 个间隔计数,如下所示

      db.data.aggregate([
          { "$group": {
              "_id": {
                  "$subtract": [
                      { "$subtract": [ "$value.count", 0 ] },
                      { "$mod": [ 
                          { "$subtract": [ "$value.count", 0 ] },
                          5
                      ]}
                  ]
              },
              "count": { "$sum": 1 }
          }}
      ])
      

      也许这里还有一个相关的question here

      【讨论】:

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