在mongodb中$ facet聚合后格式化数据

时间:2019-06-05 14:34:39

标签: node.js mongodb mongodb-query aggregation-framework

首先,在发布此问题之前,我经历了几个类似的问题,但似乎没有一个满足我的需求,或者我无法以一种对我有用的方式来解释它们。

我正在MongoDB中(使用NodeJS和Mongoose)在MongoDB中进行聚合,以执行一些分页并提供诸如总计和平均值之类的数据。

到目前为止,这是我的管道:

[
    { 
      $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,因此我希望发送类似以下的内容(没有这种array-object-array嵌套):

 {
    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 个答案:

答案 0 :(得分:2)

在管道的最后只使用一个$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,
  }}
]