【问题标题】:mongodb - left join with conditionsmongodb - 有条件的左连接
【发布时间】:2021-11-21 21:26:39
【问题描述】:

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

我希望所有部门等于“IT”的用户未参加 endAt 时间 > 175 的会议。无论是作为创建者还是接收者。 所以基本上是在最近 xxx 时间没有参加会议的人。

基于以下集合: John 将被找回,因为他是 IT 部门的一员,并且在“175”之后不再是接收者或创建者。 Jane 在 175 之后有一个 endAt 时间,并且在 IT 部门,所以不会被检索到 比尔是金融部门的,所以即使他没有,也没关系 Bob 在 175 之后有一个 endAt 时间并且在 IT 部门,因此不会被检索到 Mary 在 IT 部门,但没有参加任何会议,因此她被找回。

用户收藏:

[
  {
    _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'
  }
]

会议集:

[
  {
    _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}
                }
        }
    ])

【问题讨论】:

  • 尝试$lookup 与管道,查看mongodb文档,并删除未连接的文档,过滤掉空数组(连接结果)
  • 感谢@Takis_ 我已经尝试过并且得到了奇怪的结果。我将再次尝试并发布我的尝试。

标签: node.js mongodb mongodb-query anti-join


【解决方案1】:

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

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}
                }
        }
    ])

【讨论】:

  • 查询几乎相同,除了没有$project _id(用于在数组中保存更少的数据),您也可以将其替换为{"group" {"_id" : null}}(我认为会更好一些),因为我们不关心数据,我们只关心它是否至少加入了一个。检查数组是否为空不需要展开和检查,我们可以检查 1 个文档(而不是展开后的许多)。最重要的是 mongodb >= 5,所以它可以在查找管道的 $expr 中使用索引。
  • 感谢塔基斯提供的所有细节!
【解决方案2】:

查询

  • 匹配“IT”
  • 如果 >175 AND 则加入(两者中的任何一个(创建者/接收者)中的用户 ID)
    *它的查找管道,因为多个连接条件
  • 拒绝加入的人

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"
    ]
  }
])

【讨论】:

    【解决方案3】:

    聚合

    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

    【讨论】:

      猜你喜欢
      • 2012-02-27
      • 2017-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-18
      相关资源
      最近更新 更多