2013-12-18 4 views
1

У меня есть коллекция Монго, содержащие документы, которые выглядят следующим образом:

{ 
    "record" : "1", 
    "site_id" : "abc1", 
    "month" : "2013-12", 
    "recorded" : ISODate("2013-12-18T05:00:00.000Z"), 
    "status" : "OK", 
    "comment" : "blah blah blah..." 
} 

{ 
    "record" : "2", 
    "site_id" : "abc1", 
    "month" : "2013-12", 
    "recorded" : ISODate("2013-12-18T06:00:00.000Z"), 
    "status" : "OK", 
    "comment" : "blah blah blah..." 
} 

{ 
    "record" : "3", 
    "site_id" : "abc2", 
    "month" : "2013-12", 
    "recorded" : ISODate("2013-12-18T06:00:00.000Z"), 
    "status" : "OK", 
    "comment" : "blah blah blah..." 
} 

{ 
    "record" : "4", 
    "site_id" : "abc2", 
    "month" : "2013-12", 
    "recorded" : ISODate("2013-12-18T11:00:00.000Z"), 
    "status" : "ERROR", 
    "comment" : "something wrong" 
} 

{ 
    "record" : "5", 
    "site_id" : "abc2", 
    "month" : "2013-11", 
    "recorded" : ISODate("2013-11-17T08:00:00.000Z"), 
    "status" : "OK", 
    "comment" : "blah blah blah..." 
} 

Я хочу использовать оператор $ группы, чтобы сделать Mongoose вызова вернуть все значения последняя запись (определенная ISODate()) для данного месяца для каждого сайта site_id. Итак, в течение месяца 2013-12, я хотел бы вернуть запись 2 (последняя в 2013-12 годах для abc1) и запись 4 (последняя в 2013-12 годах для abc2).

Я могу сделать это с помощью функции map/reduce, но мне было интересно, можно ли это выполнить только с помощью API Mongoose и структуры агрегации (без вызова функции map/reduce). Я чувствую, что так должно быть, но я не смог заставить его работать!

+0

Не могли бы вы изменить вопрос, чтобы включить некоторые из попыток вы сделали и что не работает? С базой агрегации и конвейером лучше всего работать, шаг за шагом. – WiredPrairie

ответ

0

При использовании aggregate, чтобы получить конкретный элемент каждой группы необходимо включить $sort этап в вашем трубопроводе перед $group, который помещает нужный элемент первым для каждой группы, так что вы можете использовать оператор $first выбрать вне поля, которые вы хотите получить из первого документа в этой группе.

В оболочке:

db.test.aggregate(
    {$match: {month: '2013-12'}}, 
    {$sort: {recorded: -1}}, 
    {$group: { 
     _id: '$site_id', 
     record: {$first: '$record'}, 
     recorded: {$first: '$recorded'}, 
     status: {$first: '$status'}, 
     comment: {$first: '$comment'} 
    }}) 
1

Предполагая, что все документы имеют все те же поля присутствуют, вы могли бы использовать Aggregation Framework, чтобы найти «последний» рекорд по каждой группе месяца и сайта.

ПРИМЕЧАНИЕ: хотя нижеприведенный запрос возвращает ожидаемые результаты, он не слишком эффективен или не масштабируется, поэтому вы должны протестировать его с помощью репрезентативного набора данных. Подход $group должен сортировать намного больше данных на первом шаге, чем вы действительно хотите вернуть. Альтернативным подходом было бы выполнить агрегирование на сайт с использованием $sort и $limit. У MongoDB 2.4+ есть для случая использования схемы агрегации $sort, за которым следует $limit (так как известно количество найденных выше результатов для n-го уровня), поэтому несколько эффективных запросов могут иметь более низкое общее время выполнения, чем одно неэффективное.

Пример агрегации:

db.sites.aggregate(

    // Need to sort first so "last" makes sense in the $group 
    { $sort: { 
     month : 1, 
     site_id: 1, 
     recorded: 1, 
    }}, 

    // Find the last monthly record for each site_id 
    { $group: { 
     _id: { "month" : "$month", site_id: "$site_id" }, 
     record: { $last: "$record" }, 
     site_id: { $last: "$site_id" }, 
     month: { $last: "$month" }, 
     recorded: { $last: "$recorded" }, 
     status: { $last: "$status" }, 
     comment: { $last: "$comment" } 
    }} 

) 

Пример результата:

{ 
    "result" : [ 
     { 
      "_id" : { 
       "month" : "2013-12", 
       "site_id" : "abc2" 
      }, 
      "record" : "4", 
      "site_id" : "abc2", 
      "month" : "2013-12", 
      "recorded" : ISODate("2013-12-18T11:00:00Z"), 
      "status" : "ERROR", 
      "comment" : "something wrong" 
     }, 
     { 
      "_id" : { 
       "month" : "2013-12", 
       "site_id" : "abc1" 
      }, 
      "record" : "2", 
      "site_id" : "abc1", 
      "month" : "2013-12", 
      "recorded" : ISODate("2013-12-18T06:00:00Z"), 
      "status" : "OK", 
      "comment" : "blah blah blah..." 
     } 
    ], 
    "ok" : 1 
} 
Смежные вопросы