map reduce () *и * find() в одном запросе


Я нашел кучу учебников map_reduce, но ни в одном из них, кажется, нет пункта "where" в них или любого другого способа исключить документы/записи из того, что рассматривается. Я работаю над, казалось бы, простым запросом. У меня есть базовый файл журнала событий с отметками времени, ip-адресами и идентификаторами кампаний. Я хочу получить количество уникальных пользователей в пределах заданного диапазона временных меток для данной кампании. Звучит просто!

Я построил объект запроса, который является чем-то вроде это:

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

С этим я попробовал две вещи, одну используя distinct, а другую с map_reduce:

Distinct

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

В оболочке mongo вы можете поместить запрос в качестве второго параметра функции 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 делает то, что мне не нужно, я взял ее из демо). Это прекрасно работает, но не использует мои параматеры "где". Я попробую это:

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

Это кажется таким простым! Как вы делаете это в монго?

ОБНОВЛЕНИЕ: ОТВЕТ

Основываясь на ответе Дмитрия ниже, я смог решить (и упростить) мое решение (это так просто, как я могу это сделать?):

#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();

Спасибо Дмитрий!

2 4

2 ответа:

Вы можете попробовать использовать это:

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

Обновление: приведенное выше утверждение работает в оболочке mongo. В pymongo вы должны добавить запрос в качестве четвертого параметра:

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

Подробную документацию можно найтиздесь .

Не уверен, что это возможно через pymongo, руководство указывает, что это должно быть, но в оболочке mongoDB у вас есть функция 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++}
   }
);