Как суммировать различные значения поля в коллекции MongoDB (используя mongoose)

Представьте, что у меня есть коллекция под названием journals, содержащая такие документы:

{
  "article": "id1",
  "d": 2
},
{
  "article": "id1",
  "d": 2
},
{
  "article": "id1",
  "d": 3
},
{
  "article": "id2",
  "d": 2
},
...

Где d — это переключатель, а article — ссылка. Теперь я хочу получить результат, подобный следующему:

[
  {
    "_id": "id1",
    "total": 3,
    "d2": 2,
    "d3": 1
  },
  {
    "_id": "id2",
    "total": 1,
    "d2": 1,
    "d3": 0
  }
]

Я использую mongoose и имею модель под названием Journal. То, что у меня есть до сих пор, это…

Journal.aggregate(
  { $project: {
    articleId: 1,
    depth2 : { $gte:['$d', 2] },
    depth3 : { $eq:['$d', 3] }
  }},
  { $group: {
      _id: '$article',
      total: { $sum: 1 },
      d2: { $sum: '$depth2'},
      d3: { $sum: '$depth3'}
    }
  },
  function (err, journal) {
    console.log(journal);
  }
);

что приводит к:

[
  {
    "_id": "id1",
    "total": 3,
    "d2": 0,
    "d3": 0
  },
  {
    "_id": "id2",
    "total": 1,
    "d2": 0,
    "d3": 0
  }
]

Очевидно, ошибка здесь в том, что $eq:['$d', 3] не суммируется, потому что это приводит к логическому значению.

Итак, есть ли лучшее выражение, которое проецирует новые поля depth2 и depth3 в 1или 0 вместо true или false?
Или есть полный и лучший подход? :)

Я бы не хотел делать 3 запроса и добавлять соответствующую фазу, например { $match: { d: 2 } }.


person aaki    schedule 30.11.2014    source источник


Ответы (1)


Вы можете использовать $cond для преобразования логического значения в числовое значение, но у вас также есть $gte там, где должно быть $eq, и ваши документы используют article, а ваш код использует articleId:

Journal.aggregate([
  { $project: {
    article: 1,
    depth2 : { $cond: [{$eq: ['$d', 2]}, 1, 0] },
    depth3 : { $cond: [{$eq: ['$d', 3]}, 1, 0] }
  }},
  { $group: {
      _id: '$article',
      total: { $sum: 1 },
      d2: { $sum: '$depth2'},
      d3: { $sum: '$depth3'}
    }
  }
]);

Выход:

{
    "result" : [ 
        {
            "_id" : "id2",
            "total" : 1,
            "d2" : 1,
            "d3" : 0
        }, 
        {
            "_id" : "id1",
            "total" : 3,
            "d2" : 2,
            "d3" : 1
        }
    ],
    "ok" : 1
}
person JohnnyHK    schedule 30.11.2014
comment
Это как Рождество, спасибо большое! И да, вы правы насчет articleId, который появился в процессе упрощения примера. Что касается $gte, то это специально, так как это соответствует моим потребностям. Итак, d — это не совсем переключатель, я лгал об этом, но, если спросить здесь, на SO, это было описано как можно лучше :) Еще раз, спасибо за ваше время! - person aaki; 01.12.2014