You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合查询如何对分组后的嵌套对象列表进行限制与分页

解决方案

方案1:$slice 裁剪数组(轻量场景适用)

直接在聚合管道中新增$addFields阶段,使用$slice操作符对分组后的logs数组做截取,支持固定长度限制和分页逻辑,写法简单易维护。
代码示例:

const db = request.client.db( DATABASE_NAME );
// 自定义每组日志的分页参数
const groupLogsPage = 1; // 组内页码,从1开始
const groupLogsPageSize = 10; // 组内每页条数
const skipLogsCount = (groupLogsPage - 1) * groupLogsPageSize;

db.collection( COLLECTION_NAME )
    .aggregate([
        // 先对原始日志按规则排序,保证分组后数组顺序符合预期,这里示例按时间倒序
        { $sort: { time: -1 } },
        { $group : { _id : "$device.model", logs: { $push: "$$ROOT" } } } ,
        { $sort: { _id: 1 } },
        // 新增阶段:裁剪logs数组,实现长度限制/分页
        {
            $addFields: {
                logs: {
                    $slice: ["$logs", skipLogsCount, groupLogsPageSize]
                }
            }
        },
        // 根级分页移至管道内,逻辑更统一
        { $skip: 5 },
        { $limit: 2 }
    ])
    .toArray()
    .then( docs => {
        response.send({
            status: STATUS_SUCCESS,
            data: docs
        });
    });

适用场景:单分组下日志数量较少(千级以内),不需要考虑额外内存开销的场景。

方案2:$setWindowFields 预过滤(大数据量场景适用,MongoDB 5.0+支持)

先给每个设备型号分组内的日志标记序号,直接过滤出分页范围内的日志后再做聚合,避免加载多余数据,内存开销更低。
代码示例:

const db = request.client.db( DATABASE_NAME );
// 自定义每组日志的分页参数
const groupLogsPage = 1; // 组内页码,从1开始
const groupLogsPageSize = 10; // 组内每页条数
const minIndex = (groupLogsPage - 1) * groupLogsPageSize + 1;
const maxIndex = groupLogsPage * groupLogsPageSize;

db.collection( COLLECTION_NAME )
    .aggregate([
        // 按设备型号分区,分区内按时间倒序,给每个文档生成分组内序号
        {
            $setWindowFields: {
                partitionBy: "$device.model",
                sortBy: { time: -1 },
                output: {
                    groupIndex: {
                        $documentNumber: {}
                    }
                }
            }
        },
        // 过滤出当前分页范围内的日志
        {
            $match: {
                groupIndex: { $gte: minIndex, $lte: maxIndex }
            }
        },
        // 分组聚合
        { $group : { _id : "$device.model", logs: { $push: "$$ROOT" } } } ,
        { $sort: { _id: 1 } },
        // 根级分页
        { $skip: 5 },
        { $limit: 2 }
    ])
    .toArray()
    .then( docs => {
        response.send({
            status: STATUS_SUCCESS,
            data: docs
        });
    });

适用场景:单分组下日志数量较大(万级以上),对查询性能要求较高的场景。


注意事项

  • 若需要自定义分组内日志的排序规则,必须在聚合的前置阶段指定排序逻辑,避免截取的日志顺序不符合预期。
  • 根级的skip和limit放在聚合管道内和游标方法调用效果一致,放在管道内更便于排查复杂聚合逻辑的问题。

内容的提问来源于stack exchange,提问作者Vito Lipari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:06:03