如何通过MongoDB聚合管道将权限文档转为每4组一组的嵌套数组
实现MongoDB聚合结果按固定数量分组为嵌套数组
假设你已经通过$group和$project得到了单个权限组对象组成的数组,要将其转换为每4个一组的嵌套数组,可以通过添加以下聚合阶段实现:
完整聚合管道示例
[ // --- 你的原有聚合阶段 --- { $group: { _id: "$permissionGroupName", permissions: { $push: "$$ROOT" } } }, { $project: { _id: 0, permissionGroupName: "$_id", permissions: 1 } }, // --- 新增的分组转换阶段 --- // 1. 可选但建议:排序保证分组顺序稳定 { $sort: { permissionGroupName: 1 } }, // 2. 给每个文档分配分组键(每4个为一组) { $setWindowFields: { partitionBy: null, // 整个结果集作为一个分区 sortBy: { permissionGroupName: 1 }, // 和上面的排序规则一致 output: { chunkKey: { $floor: { $divide: [ { $subtract: [ { $rowNumber: {} }, 1 ] }, 4 ] } } } } }, // 3. 按分组键聚合成子数组 { $group: { _id: "$chunkKey", groupChunk: { $push: "$$ROOT" } } }, // 4. 按分组键排序,保证子数组的顺序正确 { $sort: { _id: 1 } }, // 5. 清理临时字段,保留需要的权限组数据 { $project: { _id: 0, groupChunk: { $map: { input: "$groupChunk", as: "item", in: { permissionGroupName: "$$item.permissionGroupName", permissions: "$$item.permissions" } } } } }, // 6. 将所有子数组收集到顶层嵌套数组中 { $group: { _id: null, nestedGroups: { $push: "$groupChunk" } } }, { $project: { _id: 0, nestedGroups: 1 } } ]
关键阶段说明
- $sort:MongoDB聚合结果默认无序,添加此阶段可保证后续分组的顺序稳定,避免每次执行结果的分组逻辑混乱。你可以根据实际需求调整排序字段。
- $setWindowFields:通过
$rowNumber生成每个文档的行号,再用$floor(($rowNumber-1)/4)计算分组键,这样第1-4个文档的分组键为0,第5-8个为1,以此类推,实现每4个一组的划分。 - 第一个$group:按分组键将文档聚合成子数组,每个子数组对应一组权限组。
- 第二个$sort:按分组键排序,确保最终的嵌套数组顺序和原数组的顺序一致。
- $map:清理掉临时生成的
chunkKey字段,只保留权限组的核心数据。 - 最后两个$group和$project:将所有子数组收集到一个顶层数组中,得到你需要的嵌套数组结构。
注意事项
- 如果原数组长度不是4的倍数,最后一个子数组的元素数量会少于4个,这是正常的预期结果。
- 若不需要保持原数组的顺序,可以去掉两个
$sort阶段,但不建议这么做,因为无序的分组结果可能不符合业务预期。
内容的提问来源于stack exchange,提问作者CodeR_Ax20
相关产品推荐
相关产品推荐

