【问题标题】:How to combine the results of two different queries with mongoose?如何将两个不同查询的结果与猫鼬结合起来?
【发布时间】:2020-03-25 15:03:28
【问题描述】:

我有 3 个模型(项目、组织、用户),其架构如下所示。我使用的是 mongo 4.2.0 版和 Moongoose 5.1.1 版。

问题

给定一个特定用户,我如何查询他们有权访问的所有项目:

  • 通过在项目本身中的直接角色

  • 或通过项目所属组织中的直接角色

用户可以在某个组织中担任角色,但可能不在其某个项目中。不过,查询应该能够获取这些项目(用户具有更高级别的访问权限)。

示例

Projects
[
    {    
        "_id" : ObjectId("1184f3c454b1fd6926c324fd"),
        "organizationId" : ObjectId("1284f3c454b1fd6926c324fd"),
        "roles" : [
            {
                user: ObjectId("1314f3c454b1fd6926c324fd"),
                role: 'Bar'
            }
        ]
    },
    {    
        "_id" : ObjectId("1172f3c454b1fd6926c324fd"),
        "organizationId" : ObjectId("1284f3c454b1fd6926c324fd"),
        "roles" : [
            {
                user: ObjectId("1313f4c584b1fd6926c324fd"),
                role: 'Bar'
            }
        ]
    }
]

Organizations
{    
    "_id" : ObjectId("1284f3c454b1fd6926c324fd"),
    "roles" : [
        {
            user: ObjectId("1314f3c454b1fd6926c324fd"),
            role: 'Bar'
        }
    ]
}

Users
{    
    "_id" : ObjectId("1314f3c454b1fd6926c324fd"),
    "name": "Foo"
}

备注

  • 这两个项目属于同一个组织。

  • 用户“Foo”属于该组织,但只能直接访问其中一个项目。

  • 相关查询应为用户“Foo”返回两个项目

是否应该合并两个不同的查询?

【问题讨论】:

    标签: mongodb mongoose mongoose-populate


    【解决方案1】:

    使用aggregation 管道,您可以使用这个:

    db.Projects.aggregate([
      {
        $lookup: {
          from: "Organizations",
          localField: "organizationId",
          foreignField: "_id",
          as: "organization"
        }
      },
      {
        $match: {
          $or: [
            {
              "roles.user": varSpecificUserId
            },
            {
              "organization.roles.user": varSpecificUserId
            }
          ]
        }
      }
    ]);
    

    以下是来自以下数据库数据的解释

    Projects
    [{
        "_id": "pro0",
        "organizationId": "org0",
        "roles": []
    }, {
        "_id": "pro2",
        "organizationId": "org1",
        "roles": []
    }, {
        "_id": "pro3",
        "organizationId": "org0",
        "roles": [
          {
            user: "usr2",
            role: "Foo"
          }
        ]
      }
    ]
    
    Organizations
    [{
        "_id": "org0",
        "roles": [
          {
            user: "usr0",
            role: "Foo"
          }
        ]
    }, {
        "_id": "org1",
        "roles": [
          {
            user: "usr1",
            role: "Bar"
          }
        ]
      }
    ]
    
    Users
    [{
        "_id": "usr0",
        "name": "User0"
    }, {
        "_id": "usr1",
        "name": "User1"
    }, {
       "_id": "usr2",
       "name": "User2"
    }, {
        "_id": "usr3",
        "name": "User3"
    }]
    
    • 我们打电话给varSpecificUserId specific user'_id。
    • $lookup 使用来自Projects 集合的localField 与来自Organizations 集合的foreignField 匹配查询另一个集合。
    • $lookup 的结果是所有与organizationId 匹配的Organizations 的数组,如果每个Project。该数组使用$lookup 对象的as 关键字存储在organisation。这是一个前任。这一步的查询对象:
    {
        "_id": "pro0",
        "organization": [
          {
            "_id": "org0",
            "roles": [
              {
                "role": "Foo",
                "user": "usr0"
              }
            ]
          }
        ],
        "organizationId": "org0",
        "roles": []
      },
    
    • organization 现在附加到Project,我们拥有执行查询的所有信息:

      • 通过在项目本身中的直接角色
      • 或通过项目所属组织中的直接角色
    • $match 步骤保持Projectsroles 数组中具有匹配的uservarSpecificUserId 变量ORorganization 中匹配userroles 数组。这是varSpecificUserId = "usr0"的最终查询结果:

    [
      {
        "_id": "pro0",
        "organization": [
          {
            "_id": "org0",
            "roles": [
              {
                "role": "Foo",
                "user": "usr0"
              }
            ]
          }
        ],
        "organizationId": "org0",
        "roles": []
      },
      {
        "_id": "pro3",
        "organization": [
          {
            "_id": "org0",
            "roles": [
              {
                "role": "Foo",
                "user": "usr0"
              }
            ]
          }
        ],
        "organizationId": "org0",
        "roles": [
          {
            "role": "Foo",
            "user": "usr2"
          }
        ]
      }
    ]
    

    如果 DB 中已有数据,您可以使用 https://mongoplayground.net/ 使用 mongo 查询或 MongoDB Compass 的新聚合工具。

    【讨论】:

    • 成功了,谢谢你的解释和详细的例子!
    猜你喜欢
    • 2022-12-17
    • 2017-12-03
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    • 2017-05-17
    • 2022-06-23
    • 2014-03-03
    • 1970-01-01
    相关资源
    最近更新 更多