MongoDB "JOIN" 聚合:如何在 $lookup 之后进行 $match?

MongoDB "JOIN" aggregation: How to $match after a $lookup?

我有两个集合:collAcollB,我正在进行以下查找:

db.collA.aggregate([
    {
        $lookup: {from: 'collB', localField: '_id', foreignField: 'key', as: 'bs'}
    }])

如果我们到此为止,那么 bs 是一个对象数组

每个“b”对象都有一个字段name

我只想过滤 bs 之一满足条件的记录:b.name == query_name.

  1. 我认为$elemMatch不可能
  2. 我也认为我可以 $unwind$group 但感觉像是开销。

有没有一种简单的方法可以按此条件进行筛选?

示例数据:

collA:

[
    {"_id": "1", "a": 1, "b": 1},
    {"_id": "2", "a": 2, "b": 2}
]

collB:

[
    {"key": "1", "name": "Ron"},
    {"key": "1", "name": "Bob"},
    {"key": "1", "name": "Dana"},
    {"key": "2", "name": "John"},
    {"key": "2", "name": "Ron"}
]

因此,如果查询是 Ron,我希望从 collA 获得这两个文档。如果查询是 Bob 我希望只得到带有 _id == 1

的文档

解决方案 1

$project 阶段使用 $filter 从数组 (bs) 中过滤文档。

db.collA.aggregate([
  {
    $lookup: {
      from: "collB",
      localField: "_id",
      foreignField: "refId",
      as: "bs"
    }
  },
  {
    $project: {
      _id: 1,
      bs: {
        "$filter": {
          "input": "$bs",
          "cond": {
            $eq: [
              "$$this.name",
              /* Filter value */
            ]
          }
        }
      }
    }
  }
])

Sample Solution 1 on Mongo Playground


解决方案 2

使用$lookup with pipeline.

db.collA.aggregate([
  {
    $lookup: {
      from: "collB",
      let: {
        id: "$_id"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $eq: [
                    "$$id",
                    "$refId"
                  ]
                },
                {
                  $eq: [
                    "$name",
                    /* Filter value */
                  ]
                }
              ]
            }
          }
        }
      ],
      as: "bs"
    }
  }
])

Sample Solution 2 on Mongo Playground