【发布时间】:2015-08-26 17:27:46
【问题描述】:
我正在尝试使用 php 驱动程序计算 mongo db 集合中给定记录的跳过值。因此,获取给定记录,找出该记录在整个集合中的索引。这可能吗?
目前我正在选择所有记录并手动对结果数组进行索引。
【问题讨论】:
标签: php mongodb mongodb-query mongodb-php
我正在尝试使用 php 驱动程序计算 mongo db 集合中给定记录的跳过值。因此,获取给定记录,找出该记录在整个集合中的索引。这可能吗?
目前我正在选择所有记录并手动对结果数组进行索引。
【问题讨论】:
标签: php mongodb mongodb-query mongodb-php
这称为“前向分页”,当使用“排序”结果时,您可以使用这个概念“有效地分页”通过“前向”方向的结果。
包含 JavaScript 逻辑(因为它在 shell 中工作),但不难翻译。
一般概念:
{ "_id": 1, "a": 3 },
{ "_id": 2, "a": 3 },
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
将那些“已经排序”的文档(为了方便)作为我们希望每页“分页”“两个”项目的结果示例。
在第一种情况下,您可以这样做:
var lastVal = null,
lastSeen = [];
db.collection.find().sort({ "a": -1 }).limit(2).forEach(function(doc) {
if ( lastVal != doc.a ) {
lastSeen = [];
}
lastVal = doc.a;
lastSeen.push( doc._id );
// do something useful with each document matched
});
现在,lastVal 和 lastSeen 是您存储在类似“会话变量”中的东西,可以在 Web 应用程序的下一个请求中访问,或者其他类似的东西。
它们应该包含的内容是您排序的最后一个值和“唯一”_id 值列表,因为该值没有改变。因此:
lastVal = 3,
lastSeen = [1,2];
关键是,当“下一页”的请求出现时,您希望将这些变量用于以下内容:
var lastVal = 3,
lastSeen = [1,2];
db.collection.find({
"_id": { "$nin": lastSeen },
"a": { "$lte": lastVal }
}).sort({ "a": -1 }).limit(2).forEach(function(doc) {
if ( lastVal != doc.a ) {
lastSeen = [];
}
lastVal = doc.a;
lastSeen.push( doc._id );
// do something useful with each document matched
});
这样做是从结果列表中“排除”记录在lastSeen 中的_id 的所有值,并确保所有结果都需要“小于或等于”(降序排列) 为排序字段“a”记录的lastVal。
这会在集合中产生接下来的两个结果:
{ "_id": 3, "a": 3 },
{ "_id": 4, "a": 2 },
但在处理完我们的值后,现在看起来像这样:
lastVal = 2,
lastSeen = [4];
所以现在的逻辑是,您不需要排除之前看到的其他 _id 值,因为您只是真正寻找“a”的值而不是“小于或等于”lastVal 和因为在该值处只有“一个”_id 值,所以只排除那个值。
这当然会产生使用与上面相同的代码的下一页:
{ "_id": 5, "a": 1 },
{ "_id": 6, "a": 0 }
这是通过一般结果“转发页面”的最有效方式,对于“排序”结果的高效分页特别有用。
但是,如果您想在任何阶段“跳转”到页面20 或类似操作,那么这不适合您。你被传统的.skip() 和.limit() 方法困住了,因为没有其他合理的方法可以“计算”这一点。
所以这一切都取决于您的应用程序如何实现“分页”以及您可以接受什么。 .skip() 和 .limit() 方法存在“跳过”的性能,可以通过使用此处的方法来避免。
另一方面,如果您想要“跳转到页面”,那么“跳过”是您唯一真正的选择,除非您想要构建结果的“缓存”。但这完全是另一个问题。
【讨论】: