【问题标题】:mongodb aggregate skip limit count for pagination分页的mongodb聚合跳过限制计数
【发布时间】:2018-08-08 10:37:30
【问题描述】:

我想对这个聚合数据应用分页(所有与集合 2 和 3 匹配和投影的文档)。我尝试了多次 查询,我通过了限制 25,但它只会得到 20 个文档,在此查询中需要更改以进行分页

var pipeline = [{
        $match: query
    }, {
        $limit: limit
    }, {
        $skip: skip
    }, {
        $lookup: {
            from: "collection2",
            localField: "collection1Field",
            foreignField: "collection2Field",
            as: "combined1"
        }
    }, {
        "$unwind": "$combined1"
    }, {
        $lookup: {
            from: "collection3",
            localField: "collection1Field",
            foreignField: "collection3Field",
            as: "combined2"
        }
    }, {
        "$unwind": "$combined2"
    }, {
        $project: {
            "collection1Field1": 1,
            "collection1Field2": 1,
            "collection1Field3": 1,
            "collection2Field.field1": 1,
            "collection2Field.field2": 1,
            "collection3Field.field1": 1,
            "collection3Field.field2": 1,
        }
    }
];

【问题讨论】:

    标签: mongodb pagination mongodb-query


    【解决方案1】:

    我刚刚遇到了类似的问题。由于我运行了limit,然后是skip,因此我在“第 2 页”上没有得到任何结果。

    $skip 的文档:

    跳过指定数量的进入阶段的文档 并将剩余的文档传递到管道中的下一个阶段。

    $limit 的文档:

    限制传递到下一阶段的文档数量 管道。

    这意味着如果您在skip 之前运行limit,则限制返回的结果可能会被skip 截断。

    例如,如果limit 为 50,skip 为 50(例如第 2 页),则匹配项将找到项目,将结果限制为 50,然后跳过 50,从而将 0 结果输入到之后的任何阶段.

    我不建议在查询结束时运行 $skip$limit,因为数据库将对大量数据执行管道操作,这些数据将在以下时间被跳过/限制结束。此外,可以使用的内存聚合量有一个限制,如果超出限制(100MB - 见底部),这将在错误中结束查询。如果超过此限制,可以选择启用磁盘使用,但不依赖磁盘优化代码的一个好方法是在输入任何 $lookup$unwind 步骤之前跳过 + 限制结果。

    规则的一个例外是$sort,如果$limit 紧跟$sort(文档),则它足够智能,可以使用$limit

    $sort 在管道中紧接在$limit 之前时,$sort 操作仅在进行时保持前 n 个结果,其中 n 是指定的限制,MongoDB只需要存储n项 记忆。当 allowDiskUsetrue 并且 n 个项目超过了聚合内存限制。

    根据您的代码,我会推荐以下内容(跳过然后限制):

    var pipeline = [{
        $match: query
    }, {
        $skip: skip
    }, {
        $limit: limit
    }, {
        $lookup: {
            from: "collection2",
            localField: "collection1Field",
            foreignField: "collection2Field",
            as: "combined1"
        }
    }, {
        "$unwind": "$combined1"
    }, {
        $lookup: {
            from: "collection3",
            localField: "collection1Field",
            foreignField: "collection3Field",
            as: "combined2"
        }
    }, {
        "$unwind": "$combined2"
    }, {
        $project: {
            "collection1Field1": 1,
            "collection1Field2": 1,
            "collection1Field3": 1,
            "collection2Field.field1": 1,
            "collection2Field.field2": 1,
            "collection3Field.field1": 1,
            "collection3Field.field2": 1,
        }
    }];
    

    关于聚合管道限制的文档:

    在 2.6 版中更改了内存限制。

    流水线阶段的 RAM 限制为 100 兆字节。如果一个阶段 超过此限制,MongoDB 将产生错误。为了允许 处理大型数据集,使用 allowDiskUse 选项启用 将数据写入临时文件的聚合管道阶段。

    在 3.4 版中更改。

    $graphLookup 阶段必须保持在 100 兆字节的内存限制内。 如果为aggregate() 操作指定了allowDiskUse: true,则 $graphLookup 阶段忽略该选项。如果还有其他阶段 aggregate() 操作,allowDiskUse: true 选项对 这些其他阶段。

    【讨论】:

      【解决方案2】:

      您想在获得结果后进行分页。

      var pipeline = [{
              $match: query
          }, {
              $lookup: {
                  from: "collection2",
                  localField: "collection1Field",
                  foreignField: "collection2Field",
                  as: "combined1"
              }
          }, {
              "$unwind": "$combined1"
          }, {
              $lookup: {
                  from: "collection3",
                  localField: "collection1Field",
                  foreignField: "collection3Field",
                  as: "combined2"
              }
          }, {
              "$unwind": "$combined2"
          }, {
              $project: {
                  "collection1Field1": 1,
                  "collection1Field2": 1,
                  "collection1Field3": 1,
                  "collection2Field.field1": 1,
                  "collection2Field.field2": 1,
                  "collection3Field.field1": 1,
                  "collection3Field.field2": 1,
              }
          }, {
              $limit: limit
          }, {
              $skip: skip
          }
      ];
      

      【讨论】:

        【解决方案3】:

        如果你使用一些 npm 模块 进行分页,你可以很容易地实现分页。例如,如果您使用mongoose-aggregate-paginate,那么您只需将其添加到架构中,例如...

        const mongoose = require('mongoose');
        const mongooseAggregatePaginate = require('mongoose-aggregate-
        paginate');
        
        mongoose.Promise = global.Promise;
        
        const chatSchema = new mongoose.Schema({
        text: {
            type: String,
        },
        },
         {
            collection: 'chat',
            timestamps: true
        });
        
        chatSchema.plugin(mongooseAggregatePaginate);
        const chat = mongoose.model('chat', chatSchema);
        module.exports = chat;
        

        此后每当您需要pagination,您的查询应该是

        UserCtr.get = (req, res) => {
        
            const { limit } = 10;
            const { page } = req.query.page;
        
            const aggregateRules = [{
                    $match: {
                        _id: req.user.id
                    },
                    {
                        //Perform your query
                    }
                ];
        
        
        
                Chat.aggregatePaginate(aggregateRules, {
                    page,
                    limit
                }, (err, docs,
                    pages, total) => {
                    if (!err) {
                        const results = {
                            docs,
                            total,
                            limit,
                            page,
                            pages,
                        };
                        res.status(200).json(results);
                    } else {
                        res.status(500).json(err);
                    }
                });
            };
        

        它给出了类似的响应

          {
          "docs": [
              {
                  "_id": "5a7676c938c185142f99c4c3",
              },
              {
                  "_id": "5a7676c938c185142f99c4c4",
              },
              {
                  "_id": "5a7676cf38c185142f99c4c5",
              }
          ],
          "total": 3,
          "limit": 50,
          "page": "1",
          "pages": 1
        }
        

        【讨论】:

        • 干杯,mongoose-aggregate-paginate-v2 也很好用
        猜你喜欢
        • 1970-01-01
        • 2013-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-04
        • 2020-02-17
        • 1970-01-01
        • 2020-06-11
        相关资源
        最近更新 更多