【问题标题】:Mongo aggregate lookup documents after group分组后的Mongo聚合查找文档
【发布时间】:2021-09-23 08:56:03
【问题描述】:

我对 MongoDB 还很陌生,到目前为止进展顺利。但现在我正在尝试更深入地研究并使用聚合(),但有点被它弄糊涂了。

我有以下几点:

  Link.aggregate([
    {
      $match: {
        eclipseId: link.eclipseId,
      },
    },
    {
      $lookup: {
        from: 'configitems',
        localField: 'autotaskId',
        foreignField: 'id',
        as: 'autotask',
      },
    },
    {
      $lookup: {
        from: 'companies',
        localField: 'autotask.companyId',
        foreignField: 'id',
        as: 'company',
      },
    },
    {
      $lookup: {
        from: 'billcharges',
        localField: 'eclipseId',
        foreignField: 'id',
        as: 'eclipse',
      },
    },
    {
      $group: {
        _id: '$eclipseId',
        id: { $first: '$_id' },
        company: { $first: { $arrayElemAt: ['$company', 0] } },
        eclipse: { $first: { $arrayElemAt: ['$eclipse', 0] } },
        autotask: { $first: { $arrayElemAt: ['$autotask', 0] } },
        items: {
          $push: '$$ROOT',
        },
      },
    },
    {
      $lookup: {
        from: 'subscriptions',
        let: { materialCodeID: '$materialCodeID' },
        pipeline: [
          { $match: { $expr: { $eq: ['$items.autotaskId', '$$materialCodeID'] } } },
        ],
        as: 'subscription2',
      },
    },
     {
       $project: {
         // company: 0,
         items: {
           company: 0,
           eclipse: 0,
           autotask: 0,
         },
       },
     },
  ])

我有 3 个收藏:

  • 配置项
  • 公司
  • 账单费用

$lookup 在这些工作上很好,但是我需要按eclipseId 分组并将所有匹配项推送到items 数组中。到目前为止,一切都很好。我面临的问题是,现在我可以说items 数组中的 4 个项目,我需要将每个项目添加到 subscriptions 集合中的 lookup 并保存到相关项目下的 subscription 键中

所以我想以以下格式结束:

{
  "data": {
    "_id": "4522",
    "id": "60ec62cc5fe7a94738d30f6b",
    "company": {
      //some data
    },
    "eclipse": {
      //some data
    },
    "autotask": {
      //some data
    },
    "items": [
      {
        "_id": "60ec62cc5fe7a94738d30f6b",
        "subscription": {
          //some data
        }
      },
      {
        "_id": "60ec62cc5fe7a94738d30f6c",
        "subscription": {
          //some data
        }
      }
    ]
  }
}

我尝试关注此SO Answer,但无济于事。 任何帮助将不胜感激

【问题讨论】:

    标签: mongodb mongoose aggregation-framework


    【解决方案1】:

    考虑到聚合管道中的 $lookup 数量,您应该真正考虑更改数据库的架构。查找非常昂贵,并且会降低应用程序的性能。您最好使用嵌套数据来重塑文档,而不是拆分成不同的文档并稍后查找聚合。

    如果我正确理解了您的问题,则给定查询的最佳解决方案是在最后一个 $group 阶段之后使用 $unwind 运算符:

    // Previous code ...
    
    {
      $group: {
        _id: '$eclipseId',
        id: { $first: '$_id' },
        company: { $first: { $arrayElemAt: ['$company', 0] } },
        eclipse: { $first: { $arrayElemAt: ['$eclipse', 0] } },
        autotask: { $first: { $arrayElemAt: ['$autotask', 0] } },
        items: {
          $push: '$$ROOT',
        },
      },
    },
    {
        $unwind: '$items'
    },
    
    ...
    

    这将为您在 $group 阶段推送 $$ROOT 期间创建的 items 数组中的每个条目创建一个文档。展开后,您会得到一组形状如下的文档:

    {
      _id: ...,
      company: ...,
      eclipse: ...,
      autotask: ...,
      items: {
       // Item data,
      },
    },
    

    拥有此数据形状后,您可以继续从订阅中查找:

    // Previous code ...
    
    {
        $unwind: '$items'
    },
    {
      $lookup: {
        from: 'subscriptions',
        localField: 'items.autotaskId',
        foreignField: 'materialCodeID',
        as: 'subscriptions2',
      },
    },
    ...
    

    因此,您将拥有一个具有以下结构的文档数组:

    {
      _id: ...,
      company: ...,
      eclipse: ...,
      autotask: ...,
      items: {
       // Item data,
      },
      subscriptions2: [ ... ]
    },
    

    要以您想要的方式完成和塑造数据,您可以按 _id 分组并添加包含订阅的属性项,如下所示:

     // Previous code ...
    
     {
       $unwind: '$items'
     },
     {
       $lookup: {
         from: 'subscriptions',
         localField: 'items.autotaskId',
         foreignField: 'materialCodeID',
         as: 'subscriptions2',
       },
    },
    {
      $group: {
        _id: '$_id',
        company: { $first: '$company'},
        eclipse: { $first: '$eclipse'},
        autotask: { $first: '$autotask'},
        items: { $push: {
          _id: '$items._id',
          subscription: '$subscriptions2',
        }}
      }
    },
    ...
    

    我不能保证这个解决方案会起作用,因为我无法在本地复制它来检查聚合管道上的数据是如何形成的,但鉴于你的解释,我会按照这条线做一些事情。

    【讨论】:

    • 感谢您的回答。它以不同的方式提供帮助:-) 我已经重组了我使用 mongo 的方式并且工作正常。我很想聊聊这个以及如何正确处理 mongo 结构
    猜你喜欢
    • 2019-05-23
    • 1970-01-01
    • 2015-02-27
    • 2020-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 2018-03-28
    相关资源
    最近更新 更多