这是我关于堆栈溢出的第一篇文章,不确定它是否是放置它的正确位置,但是几天来我一直在努力在 MongoDB 中正确实现非唯一和/或可为空字段的范围查询分页,所以想将其留在这里,也许其他人会需要这个。
为什么要实现这个分页? 很简单,当您拥有大量集合时,响应时间会更快。 经典的跳过和限制响应时间随着必须扫描的文档而增长(页码越大,响应越慢)
如果您想按 _id 分页,只需获取 id 大于/小于您的文档,具体取决于您想要的方向(下一页/上一页)。
下一页
[
{
$match: {
_id: {
$gt: ObjectId("YOUR_DOCUMENT_ID"),
},
},
},
{
$sort: {
_id: 1,
},
},
{
$limit: 10,
}
]
上一页
[
{
$match: {
_id: {
$lt: ObjectId("YOUR_DOCUMENT_ID"),
},
},
},
{
$sort: {
_id: -1,
},
},
{
$limit: 10,
},
{
$sort: {
_id: 1,
},
}
]
添加最终排序以确保文档按正确顺序返回。
如果您想要分页的字段不是 _id,请记住在该字段上创建索引。
当您有一个不唯一且不可为空的字段时,实现会更加具体一些。为了使其正常工作,您需要按 2 个字段进行排序,其中一个字段必须是唯一的且不能为空,就像 _id 一样。 如果您希望排序快速工作,您应该在 _id 和您选择的字段上创建复合索引。 下面的例子。
下一页
[
{
$match: {
$or: [
{
_id: {$gt: ObjectId("YOUR_DOCUMENT_ID")},
notUniqueAndNotNullableField: "Value",
},
{
notUniqueAndNotNullableField: {$gt: "Value"},
},
],
},
},
{
$sort: {
notUniqueAndNotNullableField: 1
_id: 1,
},
},
{
$limit: 10,
}
]
上一页
[
{
$match: {
$or: [
{
_id: {$lt: ObjectId("YOUR_DOCUMENT_ID")},
notUniqueAndNotNullableField: "Value",
},
{
notUniqueAndNotNullableField: {$lt: "Value"},
},
],
},
},
{
$sort: {
notUniqueAndNotNullableField: -1,
_id: -1,
},
},
{
$limit: 10,
},
{
$sort: {
notUniqueAndNotNullableField: 1,
_id: 1,
},
},
]
这是其中最复杂的一个,但似乎效果很好。 该查询有不同的查询,具体取决于您要用于比较的字段值。 (第一个用于当您的字段有值时,第二个用于当您的字段为空时)。 默认情况下,当您在 MongoDB 中按空字段排序时,它们将出现在开头,因此我们需要使用这个事实。
如果比较字段值为空,则进入下一页
[
{
$match: {
$or: [
{
_id: {$gt: ObjectId("YOUR_DOCUMENT_ID")},
nullableField: {$exists: false},
},
{
nullableField: {$exists: true},
},
],
},
},
{
$sort: {
nullableField: 1,
_id: 1,
},
},
{
$limit: 10,
}
]
如果比较字段值不为空,则进入下一页
此查询与非唯一且非空字段分页相同。
[
{
$match: {
$or: [
{
_id: {$gt: ObjectId("YOUR_DOCUMENT_ID")},
nullableField: "Value",
},
{
nullableField: {$gt: "Value"},
},
],
},
},
{
$sort: {
nullableField: 1,
_id: 1,
},
},
{
$limit: 10,
}
]
比较字段值为空时的上一页
[
{
$match: {
$or: [
{
_id: {$lt: ObjectId("YOUR_DOCUMENT_ID")},
nullableField: {$exists: false},
},
],
},
},
{
$sort: {
nullableField: -1,
_id: -1,
},
},
{
$limit: 10,
},
{
$sort: {
nullableField: 1,
_id: 1,
},
},
]
如果比较字段值不为空,则为上一页
[
{
$match: {
$or: [
{
_id: {$lt: ObjectId("YOUR_DOCUMENT_ID")},
nullableField: "Value",
},
{
nullableField: {$lt: "Value"},
},
{
nullableField: {$exists: false},
},
],
},
},
{
$sort: {
nullableField: -1,
_id: -1,
},
},
{
$limit: 10,
},
{
$sort: {
nullableField: 1,
_id: 1,
},
},
]
我尝试在 MongoDB 中基于许多不同类型的字段(唯一、非唯一和可为空)实现范围查询分页和排序。经过几天的工作已经能够完全用java实现了。
如果您像我一样使用 Java Spring 编写代码,我建议使用 Spring Data MongoDB 库。使用这个库真的很容易。
以 _id 为例获取下一页的代码。
Criteria filterCriteria = Criteria.where("_id").gt(new ObjectId("OBJECT_ID"))
Sort sort = Sort.by("_id", yourObject.getId())
List<AggregationOperation> aggregationOperations = new ArrayList<>();
aggregationOperations.add(Aggregation.match(filterCriteria));
aggregationOperations.add(Aggregation.sort(sort));
Aggregation aggregation = Aggregation.newAggregation(aggregationOperations);
mongo.aggregate(aggregation, YourObject.class, YourObject.class)