MongoDB 范围查询分页和对唯一、非唯一和可为空字段进行排序

问题描述 投票:0回答:1

这是我关于堆栈溢出的第一篇文章,不确定它是否是放置它的正确位置,但是几天来我一直在努力在 MongoDB 中正确实现非唯一和/或可为空字段的范围查询分页,所以想将其留在这里,也许其他人会需要这个。

为什么要实现这个分页? 很简单,当您拥有大量集合时,响应时间会更快。 经典的跳过和限制响应时间随着必须扫描的文档而增长(页码越大,响应越慢)

范围查询唯一且非空字段的分页(例如_id)

如果您想按 _id 分页,只需获取 id 大于/小于您的文档,具体取决于您想要的方向(下一页/上一页)。

下一页

[
  {
    $match: {
      _id: {
        $gt: ObjectId("YOUR_DOCUMENT_ID"),
      },
    },
  },
  {
    $sort: {
      _id: 1,
    },
  },
  {
    $limit: 10,
  }
]
  • 匹配 - 过滤您的文档。
  • 排序 - 顾名思义,只是对结果进行排序。
  • 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 mongodb sorting pagination
1个回答
0
投票

如果您像我一样使用 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)
© www.soinside.com 2019 - 2024. All rights reserved.