使用mongoose在Mongo中进行3层嵌套数组的$lookup操作

4

我有一个名为outsideServices的模型:

name: String,
salary: Number,
services: [
      {
        category: {
          ref: 'ServiceCategories',
          type: Schema.Types.ObjectId
        },
        types: [
          {
            ref: 'ServiceType',
            type: Schema.Types.ObjectId
          }
        ]
      }
    ]

我有一个名为incidents的模型:

  outsideServices: {
      ref: 'OutsideService',
      type: Schema.Types.ObjectId
    }

当从 API 请求 incidents 时,响应如下:

[
  {
    category: '5cf655135a1b72106777c238',
    types: ['5cf655a85a1b72106777c239']
  },
  {
    category: '5cf656525a1b72106777c23b',
    types: ['5cf656835a1b72106777c23c']
  }
];

如何查找 categoriestypes 的引用并保持响应中的结构?

到目前为止,我尝试了以下方法,但无法获得所需的结果:

aggregate.lookup({
      from: 'outsideservices',
      let: { serviceId: '$outsideServices' },
      pipeline: [
        { $match: { $expr: { $eq: ['$_id', '$$serviceId'] } } },
        {
          $lookup: {
            from: 'servicecategories',
            let: { services: '$services.category' },
            pipeline: [{ $match: { $expr: { $in: ['$_id', '$$services'] } } }],
            as: 'category'
          }
        },
        {
          $lookup: {
            from: 'servicetypes',
            let: { services: '$services.types' },
            pipeline: [
              { $match: { $expr: { $in: ['$_id', '$$services'] } } }
            ],
            as: 'types'
          }
        }
      ],
      as: 'outsideService'
    });


期望的结果类似于上面的响应,但使用填充文档而不是ObjectId
MongoDB 版本为 4.0.10
2个回答

1
您可以尝试以下聚合。使用$unwind将数组拆分,然后使用$lookup引入类别和类型,最后使用$group返回原始结构。
{
  "from":"outsideservices",
  "let":{"serviceId":"$outsideServices"},
  "pipeline":[
    {"$match":{"$expr":{"$eq":["$_id","$$serviceId"]}}},
    {"$unwind":"$services"},
    {"$lookup":{
    "from":"servicecategories",
    "localField":"services.category",
    "foreignField":"_id",
    "as":"services.category"
    }},
    {"$lookup":{
    "from":"servicetypes",
    "localField":"services.types",
    "foreignField":"_id",
    "as":"services.types"
    }},
    {"$group":{
    "_id":null,
    "services":{"$push":"$services"}
    }}
  ],
  "as":"outsideService"
}

谢谢您的回复,如果我想保留整个文档而不仅仅是响应中的{_id: null, services: [...]},我该怎么做?我尝试了以下代码:{ $group: { _id: null, services: { $push: '$services' }, doc: { $first: '$$ROOT' } } }, { $replaceRoot: { newRoot: '$doc' } }但这将导致只返回一个服务(因为 $first 的原因)。 - Stathis Ntonas
欢迎您。请在 group 和 replaceRoot 阶段之间插入 {$addFields:{“doc.services”:”$services”}}。这就是您所要求的吗? - s7vr
我已更新问题,“服务”架构具有更多属性,不仅仅是“服务”。 聚合后,我也希望将它们保留。 我可以使用$first将所有内容进行$group,然后在下一阶段中使用$project,但我还需要查找五个以上的“refs”,并使用相同的代码进行分组,这需要很多代码,它们都是大对象,我希望能有更简单的方法。 - Stathis Ntonas
抱歉,我不明白你的意思。addFields阶段会在变异/创建字段的同时保留现有字段。对于查找,您必须一次进行一项操作,没有捷径可走。如果您能提供更多细节,我可以尝试回答您的问题。 - s7vr

1
所以你正在使用mongoose schema,但是接下来要用mongoDB进行聚合。
你需要使用mongoose中的populatematch stage。 populate可以帮你连接refs等内容。

谢谢回复,我需要使用聚合功能,因为在到达这个阶段之前我会进行更多的查询。aggregate.lookup({})是使用mongoose的,我不太明白你为什么要指出我使用mongoose然后再提到mongoDB。 - Stathis Ntonas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接