对结果进行分页
在运行 MongoDB 6.0.13 + 或7.0.5 + 的Atlas 集群上,使用 Atlas Search 在参考点之后或之前按顺序检索 $search
查询结果。您可以使用 $search
searchAfter
或 searchBefore
选项按顺序遍历结果,并在应用程序中构建“下一页”和“上一页”功能。
使用
要检索分页结果,请执行以下步骤:
在要查询的字段上创建索引。
在随后的
$search
查询中使用参考点来检索结果中的下一组或上一组文档。要了解有关检索结果以构建“下一页”函数的更多信息,请参阅特定参考点后的Atlas Search 。
要了解有关检索结果以构建“上一页”函数的更多信息,请参阅特定参考点之前的Atlas Search 。
要跳转到结果中的某个页面,请将
$skip
和$limit
与$search
searchAfter
或searchBefore
选项相结合。例如,要从第 3 页跳转到第 5 页的结果,每页 10 个结果,请执行以下操作:使用
searchAfter
和第3页上最后一个结果的引用点(结果30 )来检索结果。返回第 5 页的结果(结果 41-50)。
此处,使用
$skip
和searchAfter
选项可优化查询,仅跳过 1 页结果(10 文档)。相比之下,如果使用不带$search
searchAfter
选项的$skip
,查询将跳过 4 页的结果(40 文档)。要学习;了解详情,请参阅 使用 searchAfter 和 $skip 从第 2 页跳转到第 5 页。
Considerations
当您对多个文档具有相同值的字段进行排序时,会出现并列。 MongoDB不保证绑定查询结果的排序,这可能会导致在您使用 searchAfter
和 searchBefore
时出现重复和不一致。 应用以下原则确保确定性的搜索行为:
按唯一字段对查询进行排序,防止相关性得分并列。
如果要主要按非唯一字段进行排序,请在唯一字段上添加从节点(secondary node from replica set)排序子句以提供服务决胜局。
按不可变字段对查询结果进行排序。 Atlas Search反映您在初始查询和后续查询之间对集合所做的更新。 如果您按可变字段(例如
updated_time
)排序,并在第一次和第二次查询之间更新集合,则Atlas Search可能会对相同的文档进行不同的排序。
要了解如何按不可变或唯一字段对查询结果进行排序,请参阅对 Atlas Search 结果进行排序。
如果部署了搜索节点,请考虑以下事项:
避免按
searchScore
对结果进行排序,因为它可能因搜索节点而异。为了计算
searchScore
,托管会考虑其上存在的所有文档,包括尚未从索引中删除的已删除文档。由于删除操作是在每个托管上独立进行的,因此这可能会导致searchScore
发生变化,具体取决于查询路由到哪个托管。
要在搜索节点上按 searchScore
排序时支持分页,请在MongoDB反馈引擎中对此请求投赞成票。
检索参考点
要检索某个点的查询结果,必须在 $search
查询中提供参考点。您可以在 $search
阶段之后的 $project
阶段中使用 $meta
关键字 searchSequenceToken
来检索参考点。
语法
1 [{ 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 } 7 "sort": { 8 "score": { 9 "$meta": "searchScore", _id:1 10 } 11 } 12 ... 13 }, 14 { 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }]
输出
searchSequenceToken
为结果中的每个文档生成一个基本64编码的词元。 令牌的长度随着查询的排序选项中指定的字段数量的增加而增加。 令牌不与数据库快照绑定。
除非在查询中指定 sort
选项,否则结果中的文档将按默认顺序排序。要了解如何对结果进行排序,请参阅对 Atlas Search 结果进行排序。
特定参考点后的Atlas Search
要在参考点之后搜索,您必须在 $search
查询中通过使用 searchAfter
选项和由 searchSequenceToken
生成的词元来指定参考点。仅当您重新运行由 searchSequenceToken
生成词元的 $search
查询时,才可以使用由 searchSequenceToken
生成的词元。使用词元的后续 $search
查询的语义(搜索字段和值)必须与 searchSequenceToken
生成词元的查询相同。
您可以使用searchAfter
选项在应用程序中构建“下一页”函数。 有关此操作的演示,请参阅本页上的示例。
searchAfter
语法
1 { 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 }, 7 "searchAfter": "<base64-encoded-token>", 8 "sort": { 9 "score": { 10 "$meta": "searchScore", _id:1 11 } 12 } 13 ... 14 }, 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }
输出
Atlas Search 返回结果中指定词元之后的文档。 Atlas SearchsearchSequenceToken
$project
$search
11在结果中返回为文档生成的词元,因为您在 阶段之后的 阶段中指定了 (如第 行所示)。这些词元可用作具有相同语义的另一个查询的参考点。
除非在查询中指定 sort
选项,否则结果中的文档将按默认顺序排序。要了解如何对结果进行排序,请参阅对 Atlas Search 结果进行排序。
特定参考点之前的Atlas Search
要在参考点之前Atlas Search ,您必须使用 searchBefore
选项和 searchSequenceToken
生成的词元在$search
查询中指定参考点。 仅当您重新运行 searchSequenceToken
为其生成令牌的$search
查询时,才能使用searchSequenceToken
生成的令牌。 使用该令牌的后续$search
查询的语义(Atlas Search 字段和值)必须与searchSequenceToken
为其生成令牌的查询相同。
您可以使用searchBefore
选项在应用程序中构建“上一页”函数。 要构建“上一页”函数,请结合使用以下内容:
有关此操作的演示,请参阅本页上的searchBefore
查询示例。
searchBefore
语法
1 { 2 "$search": { 3 "index": "<index-name>", 4 "<operator-name>"|"<collector-name>": { 5 <operator-specification>|<collector-specification> 6 }, 7 "searchBefore": "<base64-encoded-token>", 8 "sort": { 9 "score": { 10 "$meta": "searchScore", _id:1 11 } 12 } 13 ... 14 }, 15 "$project": { 16 { "paginationToken" : { "$meta" : "searchSequenceToken" } } 17 }, 18 ... 19 }
searchBefore
输出
Atlas Search 以相反的顺序返回结果中指定标记之前的文档。Atlas Search 还会返回结果中文档的生成标记,因为您在 $search
阶段之后的 $project
阶段中指定了 searchSequenceToken
(如 11 行所示)。这些标记可以用作具有相同语义的另一个查询的参考点。
示例
以下示例使用 sample-mflix.movies 集合,该集合具有名为 default
的带有动态映射的 Atlas Search 索引。如果加载集合并创建索引,则可以对该集合运行以下查询。
这些查询演示了如何检索参考点,然后在后续查询中使用该参考点来检索指定参考点之前和之后同一术语的其他结果。
此示例演示如何执行以下任务:
注意
默认情况下,Atlas Search 根据文档的相关性分数对结果中的文档进行排序。如果结果中的多个文档具有相同的分数,则 Atlas Search 将返回任意排序的结果。要按确定的顺序返回文档,查询会指定一个唯一字段 released
,以对结果进行排序。
示例查询使用以下管道阶段来检索第一页的结果,并检索后续查询的词元或参考点:
将结果限制为 | |
在结果中仅包括文档的
|
db.movies.aggregate([ { "$search": { "index": "pagination-tutorial", "text": { "path": "title", "query": "summer" }, "sort": { "released": 1 } } }, { "$limit": 10 }, { "$project": { "_id": 0, "title": 1, "released": 1, "genres": 1, "paginationToken" : { "$meta" : "searchSequenceToken" }, "score": { "$meta": "searchScore" } } } ])
[ { genres: [ 'Drama' ], title: "A Summer at Grandpa's", paginationToken: 'CKUdGgJgAA==', score: 2.262615203857422 }, { genres: [ 'Musical', 'Romance' ], title: 'Summer Stock', released: ISODate('1951-01-22T00:00:00.000Z'), paginationToken: 'CJsFGgkpAHw/0HT///8=', score: 3.000213623046875 }, { genres: [ 'Comedy', 'Romance' ], title: 'Smiles of a Summer Night', released: ISODate('1957-12-23T00:00:00.000Z'), paginationToken: 'CKIHGgkpAKDlpaf///8=', score: 2.0149309635162354 }, { genres: [ 'Drama' ], title: 'Violent Summer', released: ISODate('1959-11-13T00:00:00.000Z'), paginationToken: 'CI8JGgkpAJhJh7X///8=', score: 3.000213623046875 }, { genres: [ 'Drama', 'Romance' ], title: 'A Summer Place', released: ISODate('1959-11-18T00:00:00.000Z'), paginationToken: 'CLoJGgkpAGQJobX///8=', score: 2.579726457595825 }, { genres: [ 'Drama' ], title: 'The End of Summer', released: ISODate('1962-02-01T00:00:00.000Z'), paginationToken: 'CK0KGgkpAAzP18X///8=', score: 2.262615203857422 }, { genres: [ 'Drama', 'Romance' ], title: 'Summer and Smoke', released: ISODate('1962-04-01T00:00:00.000Z'), paginationToken: 'CMQKGgkpAECmB8f///8=', score: 2.579726457595825 }, { genres: [ 'Documentary', 'Sport' ], title: 'The Endless Summer', released: ISODate('1968-08-17T00:00:00.000Z'), paginationToken: 'CO4MGgkpAJjH5vX///8=', score: 2.579726457595825 }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: "Summer of '42", released: ISODate('1971-04-09T00:00:00.000Z'), paginationToken: 'CPQQGgkpAGRgUAkAAAA=', score: 2.579726457595825 }, { genres: [ 'Drama' ], title: 'That Certain Summer', released: ISODate('1972-11-01T00:00:00.000Z'), paginationToken: 'COwRGgkpAPQV0hQAAAA=', score: 2.579726457595825 } ]
要检索其他结果,请指定要检索结果的参考点。
示例查询使用以下管道阶段,利用 searchSequenceToken
之前查询同一术语时生成的令牌检索第二页的结果:
| |
将结果限制为 | |
仅包括结果中文档的
|
db.movies.aggregate([ { "$search": { "index": "pagination-tutorial", "text": { "path": "title", "query": "summer" }, "searchAfter": "COwRGgkpAPQV0hQAAAA=", "sort": { "released": 1 } } }, { "$limit": 10 }, { "$project": { "_id": 0, "title": 1, "released": 1, "genres": 1, "paginationToken" : { "$meta" : "searchSequenceToken" }, "score": { "$meta": "searchScore" } } } ])
[ { genres: [ 'Drama' ], title: 'Summer Wishes, Winter Dreams', released: ISODate('1974-09-09T00:00:00.000Z'), paginationToken: 'CMwSGgkpAECHcCIAAAA=', score: 2.262615203857422 }, { genres: [ 'Drama', 'Thriller' ], title: 'Shadows of a Hot Summer', released: ISODate('1978-09-01T00:00:00.000Z'), paginationToken: 'CPEVGgkpAGw/qz8AAAA=', score: 2.0149309635162354 }, { genres: [ 'Drama' ], title: 'Indian Summer', released: ISODate('1978-11-01T00:00:00.000Z'), paginationToken: 'CNYRGgkpAFhj5UAAAAA=', score: 3.000213623046875 }, { genres: [ 'Drama' ], title: 'Indian Summer', released: ISODate('1978-11-01T00:00:00.000Z'), paginationToken: 'CNsRGgkpAFhj5UAAAAA=', score: 3.000213623046875 }, { genres: [ 'Drama', 'Mystery' ], title: 'One Deadly Summer', released: ISODate('1983-05-11T00:00:00.000Z'), paginationToken: 'COwcGgkpAAjtIGIAAAA=', score: 2.579726457595825 }, { genres: [ 'Comedy' ], title: 'Summer Rental', released: ISODate('1985-08-09T00:00:00.000Z'), paginationToken: 'CL8fGgkpABTypHIAAAA=', score: 3.000213623046875 }, { genres: [ 'Drama', 'Romance' ], title: 'Summer', released: ISODate('1986-08-29T00:00:00.000Z'), paginationToken: 'CO0gGgkpAHCiY3oAAAA=', score: 3.5844719409942627 }, { genres: [ 'Drama', 'Thriller' ], title: 'Summer Camp Nightmare', released: ISODate('1987-04-17T00:00:00.000Z'), paginationToken: 'CNkiGgkpAHQ/CX8AAAA=', score: 2.579726457595825 }, { genres: [ 'Action', 'Crime', 'Drama' ], title: 'Cold Summer of 1953', released: ISODate('1988-06-01T00:00:00.000Z'), paginationToken: 'CNsjGgkpACjVTYcAAAA=', score: 2.262615203857422 }, { genres: [ 'Drama', 'War' ], title: 'That Summer of White Roses', released: ISODate('1989-07-11T00:00:00.000Z'), paginationToken: 'CI0mGgkpALSEc48AAAA=', score: 2.0149309635162354 } ]
要检索以前的结果,请指定要检索之前结果的参考点。
该示例查询使用了以下管道阶段,利用之前查询同一术语时由 searchSequenceToken
生成的令牌返回第一页的结果:
| |
将结果限制为 | |
仅包括结果中文档的
|
注意
默认情况下,Atlas Search 会以相反的顺序返回指定标记的查询结果,以便在参考点之前检索结果。为了按顺序返回文档,查询使用了 toArray() 和 JavaScript reverse()
方法。
db.movies.aggregate([ { "$search": { "index": "pagination-tutorial", "text": { "path": "title", "query": "summer" }, "searchBefore": "CMwSGgkpAECHcCIAAAA=", "sort": { "released": 1 } } }, { "$limit": 10 }, { "$project": { "_id": 0, "title": 1, "released": 1, "genres": 1, "paginationToken" : { "$meta" : "searchSequenceToken" }, "score": { "$meta": "searchScore" } } } ]).toArray().reverse()
[ { genres: [ 'Drama' ], title: "A Summer at Grandpa's", paginationToken: 'CKUdGgJgAA==', score: 2.262615203857422 }, { genres: [ 'Musical', 'Romance' ], title: 'Summer Stock', released: ISODate('1951-01-22T00:00:00.000Z'), paginationToken: 'CJsFGgkpAHw/0HT///8=', score: 3.000213623046875 }, { genres: [ 'Comedy', 'Romance' ], title: 'Smiles of a Summer Night', released: ISODate('1957-12-23T00:00:00.000Z'), paginationToken: 'CKIHGgkpAKDlpaf///8=', score: 2.0149309635162354 }, { genres: [ 'Drama' ], title: 'Violent Summer', released: ISODate('1959-11-13T00:00:00.000Z'), paginationToken: 'CI8JGgkpAJhJh7X///8=', score: 3.000213623046875 }, { genres: [ 'Drama', 'Romance' ], title: 'A Summer Place', released: ISODate('1959-11-18T00:00:00.000Z'), paginationToken: 'CLoJGgkpAGQJobX///8=', score: 2.579726457595825 }, { genres: [ 'Drama' ], title: 'The End of Summer', released: ISODate('1962-02-01T00:00:00.000Z'), paginationToken: 'CK0KGgkpAAzP18X///8=', score: 2.262615203857422 }, { genres: [ 'Drama', 'Romance' ], title: 'Summer and Smoke', released: ISODate('1962-04-01T00:00:00.000Z'), paginationToken: 'CMQKGgkpAECmB8f///8=', score: 2.579726457595825 }, { genres: [ 'Documentary', 'Sport' ], title: 'The Endless Summer', released: ISODate('1968-08-17T00:00:00.000Z'), paginationToken: 'CO4MGgkpAJjH5vX///8=', score: 2.579726457595825 }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: "Summer of '42", released: ISODate('1971-04-09T00:00:00.000Z'), paginationToken: 'CPQQGgkpAGRgUAkAAAA=', score: 2.579726457595825 }, { genres: [ 'Drama' ], title: 'That Certain Summer', released: ISODate('1972-11-01T00:00:00.000Z'), paginationToken: 'COwRGgkpAPQV0hQAAAA=', score: 2.579726457595825 } ]
要跳过结果并从页 2 跳转到 5,请使用 searchSequenceToken
生成的词元指定点之后您要检索结果,然后跳过结果中的 20 个文档。
示例查询使用以下管道阶段跳转到第 5 页上的结果,方法是使用 searchSequenceToken
从同一术语的先前查询中生成的令牌,并使用 $skip
和 $limit
阶段:
| |
跳过结果中指定引用点之后的 20 个文档,这是与您运行使用 searchAfter 检索页面 2 的查询的结果中的第二十个文档关联的词元。 | |
将结果限制为 | |
仅包括结果中文档的
|
db.movies.aggregate([ { "$search": { "index": "pagination-tutorial", "text": { "path": "title", "query": "summer" }, "searchAfter": "COwRGgkpAPQV0hQAAAA=", "sort": { "released": 1 } } }, { "$skip": 20 }, { "$limit": 10 }, { "$project": { "_id": 0, "title": 1, "released": 1, "genres": 1, "paginationToken" : { "$meta" : "searchSequenceToken" }, "score": { "$meta": "searchScore" } } } ])
[ { genres: [ 'Drama' ], title: 'A Storm in Summer', released: ISODate('2000-02-27T00:00:00.000Z'), paginationToken: 'CO5FGgkpAChakN0AAAA=', score: 2.262615203857422 }, { genres: [ 'Comedy', 'Romance' ], title: 'Wet Hot American Summer', released: ISODate('2002-04-11T00:00:00.000Z'), paginationToken: 'CKtIGgkpAFBUIu0AAAA=', score: 2.262615203857422 }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: 'Summer Things', released: ISODate('2002-10-09T00:00:00.000Z'), paginationToken: 'CIpPGgkpAFxzxvAAAAA=', score: 3.000213623046875 }, { genres: [ 'Adventure', 'Drama', 'Family' ], title: 'Wolf Summer', released: ISODate('2003-02-28T00:00:00.000Z'), paginationToken: 'COZWGgkpAGS6ofMAAAA=', score: 3.000213623046875 }, { genres: [ 'Animation', 'Adventure' ], title: 'Nasu: Summer in Andalusia', released: ISODate('2003-06-26T00:00:00.000Z'), paginationToken: 'CNlaGgkpAMxoAfYAAAA=', score: 2.262615203857422 }, { genres: [ 'Drama' ], title: 'Spring, Summer, Fall, Winter... and Spring', released: ISODate('2004-05-28T00:00:00.000Z'), paginationToken: 'CJ5ZGgkpAOjnyPwAAAA=', score: 1.8161234855651855 }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: 'Summer Storm', released: ISODate('2004-09-02T00:00:00.000Z'), paginationToken: 'CMVfGgkpAMRwvP4AAAA=', score: 3.000213623046875 }, { genres: [ 'Drama' ], title: 'Summer in the Golden Valley', released: ISODate('2004-10-08T00:00:00.000Z'), paginationToken: 'CNNWGgkpALTVdf8AAAA=', score: 2.0149309635162354 }, { genres: [ 'Drama', 'Romance' ], title: 'My Summer of Love', released: ISODate('2005-07-01T00:00:00.000Z'), paginationToken: 'CL5aGgkpAEyxzwQBAAA=', score: 2.262615203857422 }, { genres: [ 'Drama' ], title: 'Summer in Berlin', released: ISODate('2006-01-05T00:00:00.000Z'), paginationToken: 'CPZmGgkpANzclwgBAAA=', score: 2.579726457595825 } ]
要使用Atlas Search分面(Facet)结果群组,您必须将任何 string
字段索引为stringFacet
类型。要运行以下查询并按genres
movies
集合中的 字段对结果群组,您的索引必须类似于以下示例:
{ "mappings": { "dynamic": true, "fields": { "genres": { "type": "stringFacet" } } } } }
示例查询使用以下管道阶段:
| |
添加 | |
将结果限制为 | |
返回以下字段:
|
db.movies.aggregate([ { "$search": { "index": "pagination-tutorial", "facet": { "operator": { "text": { "path": "title", "query": "summer" } }, "facets": { "genresFacet": { "type": "string", "path": "genres" } } } } }, { "$addFields": { "paginationToken" : { "$meta" : "searchSequenceToken" } } }, { "$limit": 10 }, { "$facet": { "docs": [ { "$project": { "_id": 0, "title": 1, "released": 1, "genres": 1, "paginationToken" : 1 } } ], "meta": [ { "$replaceWith": "$$SEARCH_META" }, { "$limit": 1 } ] } }, { "$set": { "meta": { "$arrayElemAt": ["$meta", 0] } } } ])
[ { docs: [ { genres: [ 'Drama', 'Romance' ], title: 'Summer', released: ISODate('1986-08-29T00:00:00.000Z'), paginationToken: 'CO0gFf1nZUA=' }, { genres: [ 'Musical', 'Romance' ], title: 'Summer Stock', released: ISODate('1951-01-22T00:00:00.000Z'), paginationToken: 'CJsFFYADQEA=' }, { genres: [ 'Drama' ], title: 'Violent Summer', released: ISODate('1959-11-13T00:00:00.000Z'), paginationToken: 'CI8JFYADQEA=' }, { genres: [ 'Drama' ], title: 'Indian Summer', released: ISODate('1978-11-01T00:00:00.000Z'), paginationToken: 'CNYRFYADQEA=' }, { genres: [ 'Drama' ], title: 'Indian Summer', released: ISODate('1978-11-01T00:00:00.000Z'), paginationToken: 'CNsRFYADQEA=' }, { genres: [ 'Comedy' ], title: 'Summer Rental', released: ISODate('1985-08-09T00:00:00.000Z'), paginationToken: 'CL8fFYADQEA=' }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: 'Summer Things', released: ISODate('2002-10-09T00:00:00.000Z'), paginationToken: 'CIpPFYADQEA=' }, { genres: [ 'Adventure', 'Drama', 'Family' ], title: 'Wolf Summer', released: ISODate('2003-02-28T00:00:00.000Z'), paginationToken: 'COZWFYADQEA=' }, { genres: [ 'Comedy', 'Drama', 'Romance' ], title: 'Summer Storm', released: ISODate('2004-09-02T00:00:00.000Z'), paginationToken: 'CMVfFYADQEA=' }, { genres: [ 'Drama', 'Romance' ], title: 'Summer Palace', released: ISODate('2007-04-18T00:00:00.000Z'), paginationToken: 'CIRrFYADQEA=' } ], meta: { count: { lowerBound: Long('65') }, facet: { genresFacet: { buckets: [ { _id: 'Drama', count: Long('48') }, { _id: 'Romance', count: Long('20') }, { _id: 'Comedy', count: Long('19') }, { _id: 'Family', count: Long('7') }, { _id: 'Adventure', count: Long('5') }, { _id: 'Crime', count: Long('5') }, { _id: 'Mystery', count: Long('5') }, { _id: 'Thriller', count: Long('5') }, { _id: 'Horror', count: Long('4') }, { _id: 'Action', count: Long('3') } ] } } } } ]