【问题标题】:Mongoose lookup across 3 collections using foreign keyMongoose 使用外键在 3 个集合中查找
【发布时间】:2021-03-15 16:59:54
【问题描述】:

我发现了一些与此相关的问题(herehere),但我无法以我能理解如何做我需要的方式来解释答案。

我有 3 个集合:组织、用户和项目。每个项目属于一个用户,每个用户属于一个组织。我需要从用户的id返回所有属于登录用户所属组织的项目。

使用以下查询从集合中返回属于用户的项目很容易:

const projects = await Project.find({ user: req.user.id }).sort({ createdAt: -1 })

每个用户都有一个组织 ID 作为外键,我认为我需要使用 $lookup 和可能的 $unwind mongo 命令做一些事情,但与 SQL 查询不同,我真的很难理解发生了什么,因此我可以构建查询正确。

编辑:使用此查询

const orgProjects = User.aggregate(
    [
        {
            $match: { _id: req.user.id }
        },
        {
            $project: { _id: 0, org_id: 1 }
        },
        {
            $lookup: {
                from: "users",
                localField: "organisation",
                foreignField: Organisation._id,
                as: "users_of_org"
            }
        },
        {
            $lookup: {
                from: "projects",
                localField: "users_of_org._id",
                foreignField: "user",
                as: "projects"
            }
        },
        {
            $unset: ["organisation", "users_of_org"]
        },
        {
            $unwind: "$projects"
        },
        {
            $replaceWith: "$projects"
        }
    ])

似乎几乎可以工作,返回以下内容:

Aggregate {
  _pipeline: [
    { '$match': [Object] },
    { '$project': [Object] },
    { '$lookup': [Object] },
    { '$lookup': [Object] },
    { '$unset': [Array] },
    { '$unwind': '$projects' },
    { '$replaceWith': '$projects' }
  ],
  _model: Model { User },
  options: {}
}

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    假设您的文档具有类似 this 的架构,您可以使用 2 个 $lookup 阶段执行如下所示的聚合管道。

    db.users.aggregate(
    [
        {
            $match: { _id: "user1" }
        },
        {
            $project: { _id: 0, org_id: 1 }
        },
        {
            $lookup: {
                from: "users",
                localField: "org_id",
                foreignField: "org_id",
                as: "users_of_org"
            }
        },
        {
            $lookup: {
                from: "projects",
                localField: "users_of_org._id",
                foreignField: "user_id",
                as: "projects"
            }
        },
        {
            $unset: ["org_id", "users_of_org"]
        },
        {
            $unwind: "$projects"
        },
        {
            $replaceWith: "$projects"
        }
    ])
    

    【讨论】:

    • 谢谢你的回答,我会试一试——我是否需要做一个聚合管道,我不能只用一个查询来做吗?我不明白的一点是“$project: { _id: 0, org_id: 1 }”,这条线在做什么/来自哪里?
    • @bevc 您需要聚合查询才能在 mongo 中进行连接/查找。查找界面做不到。您实际上可以删除该 $project 阶段,它仍然可以工作。这只是我的一个习惯,只使用后续阶段需要的实际字段/数据。在那里,我们指定不包括用户 ID,只包括匹配用户的 org_id。如果您跳过初始投影,没什么大不了的。因为它只会匹配 1 个文档,所以内存使用甚至不会成为问题。但如果匹配阶段匹配数千个文档,那么我想一个项目是有意义的
    • @bevc 如果您完全控制架构,将org_id 存储在项目文档中将使您摆脱 1 个查找阶段。如果您将org_id 存储在登录用户的声明/会话/cookies/whatever 中,您也可以摆脱剩余的查找阶段,这样您就不必从数据库中获取它。
    • @bevc 你能把一些示例数据添加到 mongoplayground 并在这里分享链接,我会看看。
    • @bevc 给你:mongoplayground.net/p/rE4YDGJnMCp 注意:ObjectId("xyz") 无效。只有有效的 objectsid 十六进制字符串才能与 ObjectId() 一起使用。
    猜你喜欢
    • 2020-09-10
    • 1970-01-01
    • 2019-01-14
    • 2016-05-28
    • 1970-01-01
    • 2020-04-24
    • 2022-01-23
    • 1970-01-01
    • 2018-08-20
    相关资源
    最近更新 更多