【问题标题】:How to do pagination using range queries in MongoDB?如何在 MongoDB 中使用范围查询进行分页?
【发布时间】:2011-07-28 08:57:38
【问题描述】:

我可能遗漏了一些东西,因为我还在学习插件和 MongoDB,但我需要帮助来分页集合。

我有一个包含名称列表的集合。

下层牛肉
鸡胸肉 6oz
鸡胸肉 8oz
鸡胸肉 8oz
鸡胸肉 8oz
鸡胸肉随机
鸡腿
鸡里脊
鸡大腿
犹太盐

我在“ProductName,_id”上创建了一个复合索引。

我运行这个查询:

db.ProductGuideItem.find( { ProductName: { $gt: "Chicken Breast 8oz" } } ).sort({ProductName:1,_id:1}).limit(3); 

请注意,有 3 件“8oz 鸡胸肉”商品。

如果我运行该查询,我会得到...
鸡胸肉随机
鸡腿
鸡里脊

如果我正在分页并从顶部开始。查询将丢失 另外 2 个“鸡胸肉 8 盎司”。

所以如果每个页面只能有 3 个项目并且我想看到第 2 页,那么我应该看到..
鸡胸肉 8oz
鸡胸肉 8oz
鸡胸肉随机。

但我不是。它会到最后一块 8 盎司的鸡胸肉,然后从那里开始。

有没有办法解决这个问题?
另外,如果列表以相反的方式排序,我该怎么做?

【问题讨论】:

  • 您的主张是什么?返回的三行非常好,并且与您的查询相匹配,或者您期望什么以及为什么?
  • 首先放松一下。显然我没有正确解释这一点。如果每页只能有 3 个项目,我想看第 2 页,那么我应该看到 8 盎司鸡胸肉、8 盎司鸡胸肉、随机鸡胸肉。但我不是。它会去最后一个 8 盎司的鸡胸肉,然后从那里开始。
  • @Donny,IMO,RestRisiko 在这里有一点(也许不是说得那么微妙,但让我们把它留在那里)。您本可以在邮件列表上发布您的问题的链接,以便可能想在这里回答您的人可以首先检查他们计划发布的答案是否在其他地方没有建议。
  • @RestRisiko:即使这个问题已经在其他地方得到了回答,再次提问也是完全有效的,除非它已经在这里被提问和回答过。如果您发现再次阅读相同的问题很无聊,则无需单击链接。 StackOverflow 旨在成为一个社区资源,至少在概念上,这些问题旨在为不仅仅是 OP 提供答案,并且说诸如“在邮件列表上查看您的问题的答案”之类的内容并不是特别有助于实现这一目标。
  • @Donny V.:我同意@Adam Robinson 的观点。只要这里还没有被问到,你就可以在这里问。我不认为我们欠任何其他网站...

标签: mongodb pagination


【解决方案1】:

你只需要在光标上调用skip

请参阅cursor skip 上的 MongoDB 文档“这种方法可能对实现“分页”结果很有用。

这个例子取自Mongodb的example

function printStudents(pageNumber, nPerPage) {
   print("Page: " + pageNumber);
   db.students.find().skip((pageNumber-1)*nPerPage).limit(nPerPage).forEach( function(student) { print(student.name + "<p>"); } );
}

【讨论】:

【解决方案2】:

由于我分页的集合有重复的值,我不得不在 ProductName 和 id 上创建一个复合索引。

创建复合索引

db.ProductGuideItem.ensureIndex({ ProductName:1, _id:1});

这解决了我的问题。
参考:https://groups.google.com/d/msg/mongodb-user/3EZZIRJzW_A/oYH79npKZHkJ

假设您有以下价值观:

{a:1, b:1}
{a:2, b:1}
{a:2, b:2}
{a:2, b:3}
{a:3, b:1}

因此,您对基于范围的分页(页面大小为 2)执行此操作:

第一页

find().sort({a:1, b:1}).limit(2)
{a:1, b:1}
{a:2, b:1}

第二页

find().min({a:2, b:1}).sort({a:1, b:1}).skip(1).limit(2)

{a:2, b:2}
{a:2, b:3}

第三页

find().min({a:2, b:3}).sort({a:1, b:1}).skip(1).limit(2)
{a:3, b:1}

以下是 $min/max 的文档: http://www.mongodb.org/display/DOCS/min+and+max+Query+Specifiers

如果您的集合中没有重复值,则无需使用 min & max 或创建复合索引。你可以只使用 $lt & $gt。

【讨论】:

  • 我认为对于非唯一字段上的基于范围的分页来说,这是一个有趣且有用的观点。但是,如果 _id 字段是查询的一部分,我认为您的复合索引没有多大用处。原因是 _id 字段是唯一的,它会自动能够使用默认的 _id 索引而不是复合索引。原因见这里stackoverflow.com/questions/9598633/…
  • 使用这个方法时需要强制mongodb使用索引{ ProductName:1, _id:1},否则你的结果会乱序。
  • 这不适用于向用户显示分页组件(例如Page 1, Page 2, Page 3, ..., Page 10)的分页,因为您不能随机单击Page #N 链接,因为要使其正常工作,首先您对于Page #N-1,需要最后一个ObjectID。这更适合 Google+、Facebook 或 Twitter 等“无限滚动”页面。
  • 实际上,我最终为每个页面的第一项创建了索引,并将其用作从一个页面跳转到另一个页面的一种方式。我只处理了几百件物品,所以没什么大不了的。可能无法使用大型集合进行扩展。
猜你喜欢
  • 2018-05-13
  • 2014-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-09
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多