首页 > 解决方案 > Mongodb $lookup 聚合返回外部索引中的所有文档

问题描述

我有一个用户索引

[{
 username: "foo@bar,
 roleIds: [ Types.ObjectId("1234") ]
},
{
 username: "foo@moo,
}]

带一个roles

{
    "_id" : ObjectId("60465768f768621ec5828b68"),
    "name" : "admin",
    "permissionIds" : ObjectId("604657e8e715ss1f2d78b945")
}

permissions

{
    "_id" : ObjectId("604657e8e715ss1f2d78b945"),
    "name" : "view-user",
}

当我通过用户名获取用户时,我想补充角色信息。并非所有用户都有roleIds,所以我需要能够返回用户,无论他们是否有roleIds。

目前,角色查找总是返回roles索引中的每个项目!

我的想法是我通过数组查找roles索引的连接rolesroleIds_ids

然后我在该查找中进行管道处理以从角色中获取权限信息。

db.getCollection('users').aggregate([
        {
          $match: {
            'username':'foo@bar',
          }
      },
        {
          $lookup: {
            from: 'roles',
            let: {'roleIds': '_id'},
            as: 'roles',
            pipeline: [{
                $lookup: {
                  from: 'permissions',
                  let: {'permissionIds': "_id"},
                  as: 'permissions',
                  pipeline: [
                    {
                      $project: {
                        name: 1
                      }
                    }
                  ]
                }
              },{
                $project: {
                  name: 1,
                  permissions: 1
                }
              }
            ]
          }
        }
      ])

这条路线似乎只是返回索引中的所有文档,roles而不管它是否实际上是一个连接。

有什么我立即做错了吗?

标签: mongodbnosqlaggregation-frameworknosql-aggregation

解决方案


您的查询中有以下问题:

  1. 您在两个查找中都将错误的变量传递给pipeline内部。let
  2. 管道内缺少$match执行实际连接操作的阶段。
  3. roleIds使用[]using初始化为空ifNull(因为所有用户都没有该字段)。

试试这个查询:

db.getCollection('users').aggregate([
    {
        $match: {
            'username': 'foo@bar',
        }
    },
    {
        $lookup: {
            from: 'roles',
            let: { 'roleIds': { $ifNull: ["$roleIds", []] } },
            as: 'roles',
            pipeline: [
                {
                    $match: {
                        $expr: { $in: ["$_id", "$$roleIds"] }
                    }
                },
                {
                    $lookup: {
                        from: 'permissions',
                        let: { 'permissionId': "$permissionIds" },
                        pipeline: [
                            {
                                $match: {
                                    $expr: { $eq: ["$_id", "$$permissionId"] }
                                }
                            },
                            {
                                $project: {
                                    name: 1
                                }
                            }
                        ],
                        as: 'permissions'
                    }
                },
                {
                    $project: {
                        name: 1,
                        permissions: 1
                    }
                }
            ]
        }
    }
]);

推荐阅读