【问题标题】:map_reduce() *and* find() in same querymap_reduce() *和* find() 在同一个查询中
【发布时间】:2012-11-16 01:14:10
【问题描述】:

我在周围找到了一堆 map_reduce 教程,但它们中似乎都没有“where”子句或任何其他方式来排除正在考虑的文档/记录。我正在处理一个看似简单的查询。我有一个包含时间戳、IP 地址和活动 ID 的基本事件日志文件。我想在给定的时间戳范围内为给定的活动获取唯一用户的计数。听起来很简单!

我构建了一个类似这样的查询对象:

{'ts': {'$gt': 1345840456, '$lt': 2345762454}, 'cid': '2636518'}

因此,我尝试了两种方法,一种使用 distinct,另一种使用 map_reduce:

不同

db.alpha2.find(query).distinct('ip').count()

在 mongo shell 中,您可以将查询作为 distinct 函数的第二个参数,它可以在那里工作,但我了解到您不能在 pymongo 中这样做。

Map_reduce

map = Code("function () {"
        "    emit(this.ip, 1);"
        "}")
reduce = Code("function (key, values) {"
    "  var total = 0;"
    "  for (var i = 0; i < values.length; i++) {"
    "    total += values[i];"
    "  }"
    "  return total;"
    "}")

totaluniqueimp = db.alpha2.map_reduce(map, reduce, "myresults").count();

(我意识到 reduce 函数正在做我不需要的事情,我从演示中获取了它)。这很好用,但没有使用我的“where”参数。我试试这个:

totaluniqueimp = db.alpha2.find(query).map_reduce(map, reduce, "myresults").count();`

我得到这个错误:

AttributeError: 'Cursor' object has no attribute 'map_reduce'

结论

基本上,这就是我在 mysql 中尝试做的事情:

select count(*) from records where ts<1000 and ts>900 and campaignid=234 group by ipaddress

看起来很简单!你如何在 mongo 中做到这一点?

更新:答案

根据 Dmitry 在下面的回答,我能够解决(并简化)我的解决方案(这是否尽可能简单?):

#query is an object that was built above this
map = Code("function () { emit(this.ip, 1);}")
reduce = Code("function (key, values) {return 1;}")
totaluniqueimp = collection.map_reduce(map, reduce, "myresults", query=query).count();

谢谢德米特里!

【问题讨论】:

    标签: python mongodb pymongo


    【解决方案1】:

    你可以试试这个:

    totaluniqueimp = db.alpha2.map_reduce(map, reduce, {
        out: "myresults",
        query: {'ts': {'$gt': 1345840456, '$lt': 2345762454}, 'cid': '2636518'}
    }).count();
    

    更新:上面的语句在 mongo shell 中工作。在 pymongo 中,您应该将查询添加为第四个参数:

    totaluniqueimp = db.alpha2.map_reduce(map, reduce, "myresults", query={'ts': {'$gt': 1345840456, '$lt': 2345762454}, 'cid': '2636518'})
    

    详细的文档可以在here找到。

    【讨论】:

      【解决方案2】:

      不确定这是否可以通过 pymongo 实现,手册指出应该可以,但是在 mongoDB shell 中有一个 group() 函数,它可以轻松地让您在问题中重写 SQL:

      select count(*) 
        from records 
       where ts<1000 
         and ts>900 
         and campaignid=234
       group by ipaddress;
      

      作为:

      db. alpha2.group(
         { cond: { 'ts': {'$gt': 900, '$lt': 1000}, 'campaignid': '234' }
         , key: {  "ipaddress" : 1 }
         , initial: {count : 0}
         , reduce: function(doc, out){ out.count++}
         }
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-06
        • 1970-01-01
        • 2018-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多