2013-06-18 3 views
0

У меня есть массив, хранящийся в каждом документе/записи в базе данных mongo, и мне нужно вычислить оценку для каждого элемента в этом массиве и агрегировать оценки по другому полю элемента массива.Агрегирование записей в Mongo через массив

Мне сложно объяснить, что я пытаюсь сделать на английском, поэтому вот пример python того, что я ищу.

records = [ 
    {"state": "a", "initvalue": 1, "data": [{"time": 1, "value": 2}, {"time": 2, "value": 4}]}, 
    {"state": "a", "initvalue": 5, "data": [{"time": 1, "value": 7}, {"time": 2, "value": 9}]}, 
    {"state": "b", "initvalue": 4, "data": [{"time": 1, "value": 2}, {"time": 2, "value": 1}]}, 
    {"state": "b", "initvalue": 5, "data": [{"time": 1, "value": 3}, {"time": 2, "value": 2}]} 
] 


def sign(record): 
    return 1 if record["state"] == "a" else -1 


def score(record): 
    return [{"time": element["time"], "score": sign(record) * (element["value"] - record["initvalue"])} for element in record["data"]] 

scores = [] 
for record in records: 
    scores += score(record) 

sums = {} 
for score in scores: 
    if score["time"] not in sums: 
     sums[score["time"]] = 0 
    sums[score["time"]] += score["score"] 

print '{:>4} {:>5}'.format('time', 'score') 
for time, value in sums.iteritems(): 
    print '{:>4} {:>5}'.format(time, value) 

Это вычисляет несколько иную функцию оценки для состояния a и для состояния b, а затем агрегирует баллы по каждому входу времени.

Вот результат

time score 
    1  7 
    2 13 

Я пытаюсь выяснить, как сделать это в Монго, не вытягивая записи в питон и изобретать агрегацию.

Спасибо за помощь!

ответ

0

Хорошо. Я понял это. Как только я действительно понял, как работает трубопровод и о состоянии условия, все объединяется.

from pymongo import MongoClient 
client = MongoClient() 
result = client.mydb.foo.aggregate([ 
    {'$project': {'_id': 0, 'data': 1, 'initvalue': 1, 'state': 1}}, 
    {'$unwind': '$data'}, 
    {'$project': { 
     'time': '$data.time', 
     'score': {'$multiply': [ 
      {'$cond':  [{'$eq': ['$state', 'a']}, 1, -1]}, 
      {'$subtract': ['$data.value', '$initvalue']} 
     ]} 
    }}, 
    {'$group': { 
     '_id': '$time', 
     'score': {'$sum': '$score'} 
    }}, 
    {'$project': {'_id': 0, 'time': '$_id', 'score': 1}} 
]) 
for record in result['result']: 
    print record 

Это приводит к желаемому результату

{u'score': 13, u'time': 2} 
{u'score': 7, u'time': 1} 
+0

Если у вас возникли проблемы с пониманием выше команды, это может помочь. Комбинированная функция представляет собой массив («конвейер») команд. Попробуйте удалить команды из конца массива и посмотреть, как изменяется промежуточный результат. – Jon

Смежные вопросы