【问题标题】:Mongoose aggregate to get 2 variablesMongoose 聚合得到 2 个变量
【发布时间】:2019-11-20 23:13:50
【问题描述】:

我无法使用聚合来获取 2 个变量。 在我的收藏中,我想通过 createdAt 过滤掉某些文档 并将每个匹配的文档推送到数组变量中。

在那之后,我还想要第二个变量,它显示匹配的文档数量。

我设法在它们自己的聚合中将两者分开,但不知何故我无法将它们组合在一起以在 1 个聚合中工作

对象数组的那个:

const data = await MyList.aggregate([
    {
        $match: {
            createdAt: { $lt: new Date(myDate) }
        }
    },
    { $limit: 10 },
    { $skip: 20 }
]);

计数的那个:

const data = await MyList.aggregate([
    {
        $match: {
            createdAt: { $lt: new Date(myDate) }
        }
    },
    {
        $group: {
            _id: null,
            count: { $sum: 1 }
        }
    },
    { $limit: 10 },
    { $skip: 20 }
]);

所以我希望 data 变量中的内容是这样的:

{
    items: [ {...}, {...}, ...],
    count: 24
}

【问题讨论】:

    标签: node.js mongoose aggregation-framework


    【解决方案1】:

    如果您的 mongodb 服务器版本等于或大于 3.4,则可以使用 $facet 聚合:

    const data = await MyList.aggregate([
      {
        $match: {
          createdAt: { $lt: new Date(myDate) }
        }
      },
      {
        $facet: {
          items: [{ $skip: 0 }, { $limit: 10 }],
          count: [
            {
              $count: "count"
            }
          ]
        }
      }
    ]);
    
    

    这将为您提供如下结果:(项目将有 10 个项目,但计数将是符合条件的文档总数)

    [
      {
        "items": [
          {
            "_id": "5dd5182d45409447308379df",
            "createdAt": "2019-11-20T10:40:21.040Z",
            "name": "a1",
            "__v": 0
          },
          {
            "_id": "5dd5183345409447308379e0",
            "createdAt": "2019-11-20T10:40:21.040Z",
            "name": "a2",
            "__v": 0
          },
          ...
          ...
          {
            "_id": "5dd5185545409447308379e8",
            "createdAt": "2019-11-20T10:40:21.040Z",
            "name": "a10",
            "__v": 0
          }
        ],
        "count": [
          {
            "count": 21
          }
        ]
      }
    ]
    

    您可以像这样重塑这些数据:

        let result = {
          items: [],
          count: 0
        };
    
        if (data && data[0] && data[0].items.length) {
          result = {
            items: data[0].items,
            count: data[0].count[0].count
          };
        }
    

    结果如下:(客户端更容易解析)

    {
      "items": [
        {
          "_id": "5dd5182d45409447308379df",
          "createdAt": "2019-11-20T10:40:21.040Z",
          "name": "a1",
          "__v": 0
        },
        {
          "_id": "5dd5183345409447308379e0",
          "createdAt": "2019-11-20T10:40:21.040Z",
          "name": "a2",
          "__v": 0
        },
        ...
        ...
        {
          "_id": "5dd5185545409447308379e8",
          "createdAt": "2019-11-20T10:40:21.040Z",
          "name": "a10",
          "__v": 0
        }
      ],
      "count": 21
    }
    

    如果没有文档匹配,结果将是:

    {
        "items": [],
        "count": 0
    }
    

    【讨论】:

    • 嗨,谢谢你的回答,我试过了,但有两个问题:1. 即使项目没有进入项目列表,它也会计算项目,例如,如果我的数组在项目是空的,计数仍然显示一个数字,如 51(集合中的所有项目) 2.有没有办法,数据不是直接的数组?例如,如果我想获得计数,我需要做一些类似 data[0]total[0]total 的事情,这看起来不太漂亮
    • @Emre 是的,你是对的,我更新了答案,你可以检查一下吗?
    • 是的,完美,谢谢,但我们能以某种方式修复数据结构吗?因为一切都在一个数组中,例如,如果我在数组中没有项目,数据看起来像这样:[ {“items”:[],“count”:[] }],或者没有办法,那数据不在数组中?因为将这种数据直接放在我可以直接访问 object.items / object.count 的对象中会更有意义
    • 是的,我可能希望有一个解决方案,聚合直接返回干净的数据而无需我对其进行调整,但我想没有办法。我会在聚合后手动调整它,就像你的例子一样,感谢你的时间和帮助。
    • 不客气,我认为这不是什么大问题,我们可以根据需要轻松塑造结果。
    猜你喜欢
    • 2017-10-26
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 2021-06-15
    • 2023-01-04
    • 1970-01-01
    相关资源
    最近更新 更多