MongoDB - 自加入过滤器

MongoDB - Self join with filter

我有一个合集users如下:

{ "_id" : ObjectId("570557d4094a4514fc1291d6"), "email": "u1@mail.com", "user_type" : "1", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d7"), "email": "u2@mail.com", "user_type" : "2", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d8"), "email": "u3@mail.com", "user_type" : "3", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d6") }
{ "_id" : ObjectId("570557d4094a4514fc1291d9"), "email": "u4@mail.com", "user_type" : "2", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e6"), "email": "u5@mail.com", "user_type" : "3", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e7"), "email": "u6@mail.com", "user_type" : "3", "grade" : "A2", "room_id" : ObjectId("580557d4094a4514fc1291d7") }
{ "_id" : ObjectId("570557d4094a4514fc1291e8"), "email": "u7@mail.com", "user_type" : "2", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d8") }
{ "_id" : ObjectId("570557d4094a4514fc1291e9"), "email": "u8@mail.com", "user_type" : "3", "grade" : "A1", "room_id" : ObjectId("580557d4094a4514fc1291d8") }

我想找到具有 grade A2 的类型 2 用户的电子邮件 ID,以及具有相同 room_iduser_type 3(grade 确实室友无所谓)。所以结果数据应该是这样的:

{"email": "u2@mail.com", "roommates": [{"email": "u3@mail.com"}]}
{"email": "u4@mail.com", "roommates": [{"email": "u5@mail.com"}, {"email": "u6@mail.com"}]}

如何在 MongoDB 中执行此操作?我有 SQL 的背景,所以我正在考虑自连接,但我想还有其他方法可以做到。

是的,self-join users 合集的(concept/direction)是正确的。

  1. $lookup - 通过 room_id 和 return roommates 数组加入 users 集合。

  2. $match - 按 user_typegraderoommates.user_type.

    过滤文档
  3. $project - 修饰输出文档。

    3.1。 $map - 迭代 roommates 数组和 return 数组。

    3.1.1。 $filter - 在 roommates 数组中使用 user_type 过滤文档。

db.users.aggregate([
  {
    $lookup: {
      from: "users",
      localField: "room_id",
      foreignField: "room_id",
      as: "roommates"
    }
  },
  {
    $match: {
      user_type: "2",
      grade: "A2",
      "roommates.user_type": "3"
    }
  },
  {
    $project: {
      email: 1,
      roommates: {
        $map: {
          input: {
            $filter: {
              input: "$roommates",
              cond: {
                $eq: [
                  "$$this.user_type",
                  "3"
                ]
              }
            }
          },
          in: {
            email: "$$this.email"
          }
        }
      }
    }
  }
])

Sample Mongo Playground