【问题标题】:merge aggregation and find results in MongoDB合并聚合并在 MongoDB 中查找结果
【发布时间】:2019-01-17 13:28:23
【问题描述】:

我有这个模型:

const recordSchema = new Schema({
  user: {
    type: Schema.ObjectId,
    ref: 'Person',
    required: true
  },
  date: {
    type: Date,
    default: Date.now()
  },
  time: {
    type: Date,
    default: Date.now()
  }
});

所以,当我发出 HTTP Get 请求时,我会收到一组记录:

[{/*record1*/}, {/*record2*/}, ...]

关键是我正在使用聚合来获取每个用户的记录数(我得到了那个封面),但我想将它与查找结果合并以接收如下内容:

{
  "records": [{/*record1*/}, {/*record2*/}, ...],
  "stats": [
    { 
      "_id" : ObjectId("5b6393f2a1d3de31d9547f63"),
      "count" : 3.0
    },
    { 
      "_id" : ObjectId("5b5d22d8b6195d1b6a5d2574"),
      "count" : 17.0
    }
  ]
}

那么,我该如何获得呢?

注意:我将它用于某些图表的数据,我应该在节点上还是在前端处理它?

【问题讨论】:

  • 您的 MongoDB 服务器版本是多少?
  • 我有版本 3.6.3

标签: node.js mongodb express mongoose aggregation-framework


【解决方案1】:

这可以在后端完成,如果您在后端使用 MongoDB Server 3.4.4 或更高版本,$facet 聚合管道应该可以满足您的需求。

考虑以下示例,它使用 $facet 在同一聚合管道中运行两个聚合查询:一个返回今天的记录,另一个返回集合中每个用户的计数: p>

let start = new Date();
start.setHours(0,0,0,0);

let end = new Date();
end.setHours(23,59,59,999);

Record.aggregate([
    { '$facet': {
        'records': [
            { '$match': { 
                'date': {
                    '$gte': start,
                    '$lte': end
                }
            } }
        ],
        'stats': [
            { '$group': { 
                '_id': '$user',
                'count': { '$sum': 1 }
            } }
        ]
    } }
]).exec((err, results) => {
    if (err) {
        console.error(err);
        throw new Error(err);
    }

    const data = results[0];
    console.log(JSON.stringify(data, null, 4));
})

对于 MongoDB 3.2 及以下版本

1.使用承诺

const recordsQuery = Record.find({ 'date': {
    '$gte': start, // date object representing start of today
    '$lte': end    // date object representing end of today
} }).lean().exec();

const statsQuery = Record.aggregate([
    { '$group': { 
        '_id': '$user',
        'count': { '$sum': 1 }
    } }
]).exec();

Promise.all([ recordsQuery, statsQuery ]).then(([ recordsData, statsData ]) => {
    const records = recordsData[0];
    const stats = statsData[0];

    const data = { records, stats };
    console.log(JSON.stringify(data, null, 4));
}).catch(err => console.error(err));

2。使用异步/等待

(async () =>  {
    try {
        const recordsQuery = await Record.find({ 'date': {
            '$gte': start, // date object representing start of today
            '$lte': end    // date object representing end of today
        } }).lean().exec();

        const statsQuery = await Record.aggregate([
            { '$group': { 
                '_id': '$user',
                'count': { '$sum': 1 }
            } }
        ]).exec();

        const records = recordsQuery[0];
        const stats = statsQuery[0];

        const data = { records, stats };
        console.log(JSON.stringify(data, null, 4));
    } catch (err) {
        console.error(err);
    }
})();

【讨论】:

    【解决方案2】:

    您可以使用 $lookup 运算符按 Id 链接用户的原始记录

    {
       $lookup:
         {
           from: <collection to join>,
           localField: <field from the input documents>,
           foreignField: <field from the documents of the "from" collection>,
           as: <output array field>
         }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-04-23
      • 2019-04-09
      • 1970-01-01
      • 2019-01-14
      • 1970-01-01
      • 2021-10-26
      • 2020-08-20
      • 1970-01-01
      • 2017-05-05
      相关资源
      最近更新 更多