mongodb - 有条件的左连接

mongodb - left join with conditions

我正在尝试对这两个 collections 进行左反连接。

我希望部门等于 'IT' 的所有用户不在 endAt 时间 > 175 的会议中。作为创建者或接收者。 所以基本上谁在上次 xxx 时间没有参加会议。

基于以下 collections: John 将被检索到,因为他属于 IT 部门,并且在“175”之后不是接收者或创建者。 Jane 在 175 之后有一个 endAt 时间并且在 IT 中所以不会被检索 比尔是财务部门的一部分,所以即使他不是财务部门也没关系 Bob 在 175 之后有一个 endAt 时间并且在 IT 中所以不会被检索 玛丽在 IT 部门,没有参加任何会议,所以她被找回了。

用户Collection:

[
  {
    _id: ObjectId("1"),
    name: "john",
    department: 'IT'
  },
  {
    _id: ObjectId("2"),
    name: "jane",
    department: 'IT'
  },
  {
    _id: ObjectId("3"),
    name: "bill",
    department: 'finance'
  },
  {
    _id: ObjectId("4"),
    name: "Bob",
    department: 'IT'
  },
  {
    _id: ObjectId("5"),
    name: "Mary",
    department: 'IT'
  }
]

会议Collection:

[
  {
    _id: ObjectId("a"),
    endedAt: 100,
    creator_id: ObjectId("1"),
    receiver_id: ObjectId("2")
  },
  {
    _id: ObjectId("b"),
    endedAt: 150,
    creator_id: ObjectId("1"),
    receiver_id: ObjectId("3")
  },
  {
    _id: ObjectId("c"),
    endedAt: 200,
    creator_id: ObjectId("4"),
    receiver_id: ObjectId("2")
  },
  {
    _id: ObjectId("d"),
    endedAt: 250,
    creator_id: ObjectId("2"),
    receiver_id: 
  }
]

输出:

[
  {
    _id: ObjectId("1"),
    name: "john",
    department: 'IT'
  },
  {
    _id: ObjectId("5"),
    name: "Mary",
    department: 'IT'
  }
]

我的做法:

db.users.aggregate([
        {
            $match:
                {
                    type: 'IT'
                }
        },
        {
            $lookup:
                {
                    from: "meetings",
                    let:
                        {
                            userid: "$_id",
                        },
                    pipeline: [
                        { $match:
                                { $expr:
                                    {
                                        $and:[
                                            {
                                                $or: [
                                                    { $eq: ["$receiver_id", "$$userid"] },
                                                    { $eq: ["$creator_id", "$$userid"] },
                                                ]
                                            },
                                            { $gt: ["$endAt", 175] }
                                        ]
                                    }
                                }
                        }
                        ],
                    as: "result"
                }
        },

        {
            $unwind:
                {
                    path: "$result",
                    preserveNullAndEmptyArrays: true
                }
        },

        {
            $match:
                {
                    result: {$exists:false}
                }
        }
    ])

汇总

db.users.aggregate([
  {
    "$match": {
      department: "IT"
    }
  },
  {
    "$lookup": {
      "from": "meeting",
      "localField": "_id",
      "foreignField": "creator_id",
      "as": "meeting_creator"
    }
  },
  {
    "$lookup": {
      "from": "meeting",
      "localField": "_id",
      "foreignField": "receiver_id",
      "as": "meeting_receiver"
    }
  },
  {
    "$match": {
      "$and": [
        {
          "meeting_creator.endedAt": {
            "$not": {
              "$gt": 175
            }
          }
        },
        {
          "meeting_receiver.endedAt": {
            "$not": {
              "$gt": 175
            }
          }
        }
      ]
    }
  },
  {
    "$project": {
      _id: 1,
      name: 1,
      department: 1
    }
  }
])

数据

db={
  "users": [
    {
      _id: "1",
      name: "john",
      department: "IT"
    },
    {
      _id: "2",
      name: "jane",
      department: "IT"
    },
    {
      _id: "3",
      name: "bill",
      department: "finance"
    },
    {
      _id: "4",
      name: "Bob",
      department: "IT"
    },
    {
      _id: "5",
      name: "Mary",
      department: "IT"
    }
  ],
  "meeting": [
    {
      _id: "a",
      endedAt: 100,
      creator_id: "1",
      receiver_id: "2"
    },
    {
      _id: "b",
      endedAt: 150,
      creator_id: "1",
      receiver_id: "3"
    },
    {
      _id: "c",
      endedAt: 200,
      creator_id: "4",
      receiver_id: "2"
    },
    {
      _id: "d",
      endedAt: 250,
      creator_id: "2",
      receiver_id: ""
    }
  ]
}

结果

[
  {
    "_id": "1",
    "department": "IT",
    "name": "john"
  },
  {
    "_id": "5",
    "department": "IT",
    "name": "Mary"
  }
]

mongoplayground

查询

  • 匹配“IT”
  • 加入如果 >175 AND(userid 在任何 2 (creator/receiver))
    *它的查找管道,因为 multiple join creteria
  • 拒绝加入的

Test code here

db.users.aggregate([
  {
    "$match": {
      "department": {
        "$eq": "IT"
      }
    }
  },
  {
    "$lookup": {
      "from": "meetings",
      "let": {
        "userid": "$_id"
      },
      "pipeline": [
        {
          "$match": {
            "$expr": {
              "$and": [
                {
                  "$gt": [
                    "$endedAt",
                    175
                  ]
                },
                {
                  "$or": [
                    {
                      "$eq": [
                        "$$userid",
                        "$creator_id"
                      ]
                    },
                    {
                      "$eq": [
                        "$$userid",
                        "$receiver_id"
                      ]
                    }
                  ]
                }
              ]
            }
          }
        },
        {
          "$project": {
            "_id": 1
          }
        }
      ],
      "as": "meetings"
    }
  },
  {
    "$match": {
      "$expr": {
        "$eq": [
          "$meetings",
          []
        ]
      }
    }
  },
  {
    "$unset": [
      "meetings"
    ]
  }
])

这是我想出的最终有效的解决方案,有人知道什么是最有效的吗?

db.users.aggregate([
        {
            $match:
                {
                    type: 'IT'
                }
        },
        {
            $lookup:
                {
                    from: "meetings",
                    let:
                        {
                            userid: "$_id",
                        },
                    pipeline: [
                        { $match:
                                { $expr:
                                    {
                                        $and:[
                                            {
                                                $or: [
                                                    { $eq: ["$receiver_id", "$$userid"] },
                                                    { $eq: ["$creator_id", "$$userid"] },
                                                ]
                                            },
                                            { $gt: ["$endAt", 175] }
                                        ]
                                    }
                                }
                        }
                        ],
                    as: "result"
                }
        },

        {
            $unwind:
                {
                    path: "$result",
                    preserveNullAndEmptyArrays: true
                }
        },

        {
            $match:
                {
                    result: {$exists:false}
                }
        }
    ])