Mongo多个$ lookup和$ group聚合

时间:2017-05-09 16:23:04

标签: mongodb aggregation-framework

所以我试图在查询中“加入”3个不同的mongo集合。所以我需要的是mongo聚合中的多个$lookup$group语句。

我的3个系列看起来像这样:

用户:(伪代码)

{
  _id,
  username: String,
  group: <some group._id>
}

基团:

{
  _id,
  name: String,
  _parent: <another group._id>,
}

列表(这些是用户拥有的“商品列表”):

{
  _id,
  name: String,
  userId: <some user._id>
}

所以我想做的是,给定一些组ID或null(对于没有父级的组 - 最高级别的组) - 获取该组内的所有groups,找到所有这些群组中的users以及lists

所以最后我需要这样的东西:

[
  {
    _id: someGroupId,
    name: someGroupName,
    type: "group",
    users: [
      {
        _id: someUserId,
        name: someUserName,
        type: "user",
        lists: [
          ... and the same again for the lists (type: "list")
        ]
      },
      ... another user
    ]
  },
  ... another group
]

我希望你理解我的意思!

我现在拥有的(感谢Simon Tretter和大量研究) - 请不要介意Meteor不可知的语法,你明白了:

Groups.aggregate([
    { $match: { _parent: groupId } },
    { $sort: { name: 1 } },
    {
        $lookup: {
            from: 'users',
            localField: '_id',
            foreignField: 'group',
            as: 'users'
        }
    },
    {
        $unwind: {
            path: "$users",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $lookup: {
            from: 'lists',
            localField: 'users._id',
            foreignField: 'userId',
            as: 'users.lists'
        }
    },
    {
        $unwind: {
            path: "$users.lists",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $match: {
            $or: [
                { "users.lists": { $exists: false } },
                { "users.lists.supplier_id": supplierId }
            ]
        }
    },
    { $sort: { "users.lists.name": 1 } },
    {
        $project: {
            "name": 1,
            "type": { $literal: 'group' },
            "users._id": 1,
            "users.name": { $ifNull: ["$users.profile.company.name", "$users.username"] },
            "users.type": { $literal: 'user' },
            "users.lists._id": 1,
            "users.lists.name": 1,
            "users.lists.item_count": 1,
            "users.lists.type": { $literal: 'list' }
        }
    },
    {
        $group: {
            _id: '$users._id',
            name: { $first: "$users.name" },
            type: { $first: "$users.type" },
            children: {
                $push: "$users.lists"
            }
        }
    },
    { $sort: { "users.name": 1 } },
    // until here I have one document per user, with their lists inside the "children" key - all good!
    // now I have to group the users inside their groups ...
    // NOT WORKING: returns completely wrong stuff
    { $group: {
      _id: '$_id',
      name: { $first: "$name" },
      type: { $first: "$type" },
      children: {
        $push: "$users"
      }
    } },
    { $sort: { name: 1 } }
]);

我希望有人可以让我走上正确的轨道......我能找到的最好的similar stackoverflow question并没有帮助我。

非常感谢,P

3 个答案:

答案 0 :(得分:2)

感谢@Veeram的帮助和一点点调整,我得到了以下工作代码:

Groups.aggregate([
    { $match: { _parent: groupId } },
    { $sort: { name: 1 } },
    {
        $lookup: {
            from: 'users',
            localField: '_id',
            foreignField: 'group',
            as: 'users'
        }
    },
    {
        $unwind: {
            path: "$users",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $lookup: {
            from: 'lists',
            localField: 'userId',
            foreignField: 'users._id',
            as: 'users.lists'
        }
    },
    {
        $unwind: {
            path: "$users.lists",
            preserveNullAndEmptyArrays: true
        }
    },
    {
        $match: {
            $or: [
                { "users.lists": { $exists: false } },
                { "users.lists.supplier_id": supplierId }
            ]
        }
    },
    { $sort: { "users.lists.name": 1 } },
    {
        $project: {
            "name": 1,
            "type": { $literal: 'group' },
            "users._id": 1,
            "users.name": { $ifNull: ["$users.profile.company.name", "$users.username"] },
            "users.type": { $literal: 'user' },
            "users.lists._id": 1,
            "users.lists.name": 1,
            "users.lists.item_count": 1,
            "users.lists.type": { $literal: 'list' }
        }
    },
    {
        $group: {
            _id: {
                _id: "$_id",
                name: "$name",
                type: "$type",
                user_id: "$users._id"
            },
            user_id: {
                $first: "$users._id"
            },
            name: {
                $first: "$users.name"
            },
            type: {
                $first: "$users.type"
            },
            children: {
                $push: "$users.lists"
            }
        }
    },
    { $sort: { name: 1 } },
    {
        $group: {
            _id: "$_id._id",
            name: {
                $first: "$_id.name"
            },
            type: {
                $first: "$_id.type"
            },
            children: {
                $push: {
                    _id: "$user_id",
                    name: "$name",
                    type: "$type",
                    children: "$children"
                }
            }
        }
    },
    { $sort: { name: 1 } }
]);

答案 1 :(得分:1)

未经测试,但我会尝试这样的事情:

db.groups.aggregate(
[
  { $match: { _parent: groupId } },
  {
     $lookup: {
            from: 'users',
            localField: '_id',
            foreignField: 'group',
            as: 'users'
     }
  },  
  { $unwind: "$users" },
  { $lookup: {
    from: 'lists',
    localField: 'userId',
    foreignField: 'users._id',
    as: 'users.lists'
   }
  },
  { $group: {
    _id: "$_id",
    groupname: { $first: "$name" },
    users: {
      $push: "$users"
   }
  } }
])

答案 2 :(得分:1)

您必须在评论后使用group中的_id: {_id: "$_id", name: "$name", type: "$type", user_id: "$users._id" }$group)信息。

这样的东西
{
    $group: {
        _id: {
            _id: "$_id",
            name: "$name",
            type: "$type",
            user_id: "$users._id"
        },
        name: {
            $first: "$users.name"
        },
        type: {
            $first: "$users.type"
        },
        children: {
            $push: "$users.lists"
        }
    }
}, {
    $sort: {
        name: 1
    }
}, {
    $group: {
        _id: "$_id._id",
        name: {
            $first: "$_id.name"
        },
        type: {
            $first: "$_id.type"
        },
        users: {
            $push: {
                 _id:"$user_id",
                 name: "$name",
                 type: "$type",
                children: "$children"
            }
        }
    }
}