对集合进行排序和分页

时间:2015-07-01 13:42:22

标签: mongodb sorting pagination

如何对按非唯一字段排序的查询进行分页?例如,集合中的文档可能是(按s:1排序,然后是_id:-1):

import UIKit
var typingSpace = 80

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBOutlet weak var typingSpace: UIView!

@IBOutlet weak var displayLabel: UILabel!

}

有一个简单的限制/跳过方法可以......慢慢地工作。

是否可以使用以下内容:

{_id: 19, s: 3},
{_id: 17, s: 3},
{_id: 58, s: 4},
// etc...

检索

db.collection.find()
  .sort({s:1, _id:-1})
  .min({s:3, _id:17})    // this does not work as wanted!
  .limit(2);

2 个答案:

答案 0 :(得分:5)

如果您想通过"页码"进行分页。然后,在对密钥进行排序后,您几乎完全坚持使用.limit().skip()方法。你可能已经做了一些阅读,发现它并不是非常有效",主要是因为"跳过"通过" n"结果是为了达到某个页面。

但原则在你需要的地方是合理的:

db.collection.find().sort({ "s": -1, "_id": 1 }).skip(<page-1>).limit(<pageSize>)

如果您只需要移动&#34;前进&#34;在你的分页中,有一个更快的替代方法,也可以用于&#34;排序&#34;结果

关键是要保持对最后一次出现的&#34;&#34;价值&#34; s&#34;然后通常是_id值的列表,直到&#34; s&#34;的值为止。变化。所以使用一些文档进行演示,这些文档已经过分类以便进行演示:

{ "_id": 1, "s": 3 },
{ "_id": 2, "s": 3 },
{ "_id": 3, "s": 3 },
{ "_id": 4, "s": 2 },
{ "_id": 5, "s": 1 },
{ "_id": 6, "s": 1 },

为了获得第一页&#34; &#34;两个&#34;结果您的第一个查询很简单:

db.collection.find().sort({ "s": -1, "_id": 1}).limit(2)

但请遵循这一点来处理文件:

var lastVal = null,
    lastSeen = [];

db.collection.find().sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
    if ( doc.s != lastVal ) {    // Change when different
        lastVal = doc.s;
        lastSeen = [];
    }
    lastSeen.push(doc._id);      // Push _id onto array
    // do other things like output
})

因此,在第一次迭代时,lastVal值将为3,而lastSeen将包含数组_id中的两个文档[1,2]值。 这些东西你会存储在等待下一页请求的用户会话数据中。

根据您对下一页设置的请求,您可以按如下方式发出:

var lastVal = 3,
    lastSeen = [1,2];

db.collection.find({ 
    "_id": { "$nin": lastSeen }, 
    "s": { "$lte": lastVal }
}).sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
    if ( doc.s != lastVal ) {    // Change when different
        lastVal = doc.s;
        lastSeen = [];
    }
    lastSeen.push(doc._id);      // Push _id onto array
    // do other things like output
})

要求选择&#34; s&#34;需要从一个值&#34;小于或等于&#34; (由于排序的方向)记录了lastVal,并且&#34; _id&#34;字段不能包含lastSeen中记录的值。

生成的下一页是:

{ "_id": 3, "s": 3 },
{ "_id": 4, "s": 2 },

但现在如果您遵循逻辑,lastVal当然是2lastSeen现在只有单个数组元素[4]。由于下一个查询只需要从2继续作为一个较小或相等的值,因此不需要保留其他先前看过的&#34; _id&#34;因为它们不在该选择范围内。

然后这个过程紧随其后:

var lastVal = 2,
    lastSeen = [2];

db.collection.find({ 
    "_id": { "$nin": lastSeen }, 
    "s": { "$lte": lastVal }
}).sort({ "s": -1, "_id": 1}).limit(2).forEach(function(doc) {
    if ( doc.s != lastVal ) {    // Change when different
        lastVal = doc.s;
        lastSeen = [];
    }
    lastSeen.push(doc._id);      // Push _id onto array
    // do other things like output
})

因此,通过遵循这种逻辑模式,您可以&#34;存储&#34;从您的&#34; previousc页面找到的信息&#34;结果和移动&#34;前进&#34;通过非常有效的结果。

但是如果你需要跳到&#34;第20页&#34;或类似的操作类型,然后您会遇到.limit().skip()。它的速度比较慢,但这取决于你能忍受的东西。

答案 1 :(得分:-2)

db.t1.drop()
db.t1.save({_id:19, s:3})
db.t1.save({_id:17, s:3})
db.t1.save({_id:58, s:4})

db.t1.find().sort({s:1, _id:-1}).skip(1).limit(2)

--Result
{ "_id" : 17, "s" : 3 }
{ "_id" : 58, "s" : 4 }

- $