Форматирование данных после агрегации $ facet в mongodb - PullRequest
1 голос
/ 05 июня 2019

Прежде всего, перед тем, как опубликовать этот вопрос, я прошел через несколько похожих вопросов, и ни один из них не соответствовал моим потребностям, или я не смог истолковать их так, чтобы это помогло мне.

Я работаю с агрегацией в MongoDB (с NodeJS и Mongoose), чтобы выполнить некоторую нумерацию страниц, а также предоставить некоторые данные, такие как общее и среднее.

Пока это мой трубопровод:

[
    { 
      $match: { 
        // Some filtering criteria here
      }
    },
    { $facet: {
        metadata: [ 
          { $count: 'total' }
        ],
        avg: [
          {
            $group: {
              _id: null,
              avg_price: {
                $avg: "$price"
              }
            }
          }
        ],
        data: [ 
          { $sort: { createdDate: -1 }}, 
          { $skip: skip || 0 },
          { $limit: limit } 
        ]
      } 
    }
  ] 

Что дает мне вывод со следующей структурой:

[
    {
      "metadata": [
        {
          "total": 14
        }
      ],
      "avg": [
        {
          "_id": null,
          "avg_price": 936711.3571428572
        }
      ],
      "data": [
        // the returned data according to $match, $sort, $skip and $limit
      ]
    }
]

Я должен отправить эти данные внешнему интерфейсу, но эта структура не подходит для моих нужд. Я использую GraphQL, и я бы предпочел отправить что-то вроде следующего (без вложенности типа «массив-объект-массив»):

 {
    total: 14,
    avg_price: 936711.3571428572,
    data: [
      // the returned data according to $match, $sort, $skip and $limit
    ]
  }

Я действительно мог бы иметь некоторую логику Javascript для извлечения этих данных из результата агрегации и генерирования ожидаемого результата, но для этого потребовался бы грязный код, такой как:

avg_price: aggr_result[0].avg[0].avg_price

И я хочу этого избежать.

Мне было интересно, каким будет MongoDB способ такого форматирования в конвейере.

Спасибо за ваше время.

1 Ответ

2 голосов
/ 05 июня 2019

Просто используйте одну $project ступень в конце трубопровода

[
  { "$match": { ... }},
  { "$facet": {
      "metadata": [
        { "$count": "total" }
        ],
      "avg": [
        { "$group": {
          "_id": null,
          "avg_price": { "$avg": "$price" }
        }}
      ],
      "data": [
        { "$sort": { "createdDate": -1 }},
        { "$skip": skip || 0 },
        { "$limit": limit }
      ]
    }
  },
  { "$project": {
    "total": { "$arrayElemAt": ["$metadata.total", 0] },
    "avg_price": { "$arrayElemAt": ["$avg.avg_price", 0] },
    "data": 1,
  }}
]
...