在运行MongoDB 7.0.5+ 的集群上,使用MongoDB Search 在参考点之后或之前按顺序检索$search查询结果。使用 $search searchAfter 或 searchBefore 选项按顺序遍历结果,并在应用程序中构建“下一页”和“上一个”函数。
使用
要检索分页结果,请执行以下步骤:
在要查询的字段上创建索引。
在随后的
$search查询中使用参考点来检索结果中的下一组或上一组文档。要了解有关检索结果以构建“下一页”函数的更多信息,请参阅特定参考点后的Atlas Search 。
要了解有关检索结果以构建“上一页”函数的更多信息,请参阅特定参考点之前的Atlas Search 。
要跳转到结果中的某个页面,请将
$skip和$limit与$searchsearchAfter或searchBefore选项相结合。例如,要从第 3 页跳转到第 5 页的结果,每页 10 个结果,请执行以下操作:使用
searchAfter和第3页上最后一个结果的引用点(结果30 )来检索结果。返回第 5 页的结果(结果 41-50)。
此处,使用
$skip和searchAfter选项可优化查询,只跳过 1 页结果(10 个文档)。相比之下,如果使用$skip而不使用$searchsearchAfter选项,查询将跳过 4 页结果( 40 个文档)。要了解更多信息,请参阅使用 searchAfter 和 $skip 从第 2 页跳转到第 5 页。
Considerations
当您对多个文档具有相同值的字段进行排序时,会出现并列。 MongoDB不保证绑定查询结果的排序,这可能会导致在您使用 searchAfter 和 searchBefore 时出现重复和不一致。应用以下原则减少相关性得分联系:
如果要主要按非唯一字段进行排序,请在唯一字段上添加从节点(secondary node from replica set)排序子句以提供服务决胜局。
在查询之间更新或删除文档可能会导致结果顺序不一致。应用以下原则来支持确定性搜索行为:
按不可变字段对查询结果进行排序,例如
_id。 MongoDB搜索反映了您在初始查询和后续查询之间对集合所做的更新。如果您按可变字段(例如updated_time)排序,并在第一次和第二次查询之间更新集合, MongoDB Search 可能会对相同的文档进行不同的排序。如果您部署了专用搜索节点并且按
searchScore对结果进行排序,请考虑以下事项:默认下, MongoDB搜索使用
bm25相似度算法对文档进行评分,该算法可计算与MongoDB搜索节点上整个文档语料库相关的术语频率。由于每个MongoDB搜索节点都独立从变更流复制,因此该语料库可能因MongoDB搜索节点而异。因此,同一查询在路由到不同的MongoDB搜索节点时,可能会返回不同的bm25分数。如果您的部署使用专用的MongoDB搜索节点,或者您的读取偏好(read preference)设立为secondary或 ,则后续查询更有可能路由到不同的MongoDB搜索节点。nearest为了确保后续查询的分数一致,当您将字段索引为MongoDB搜索字符串或自动完成类型时,请将
similarity.type属性设立为stableTflboolean或 。这会强制 text、phrase、queryString 和 autocomplete 操作符使用stableTfl或boolean相似度算法来计算索引字段查询的相关性分数。这些算法在所有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" 10 } 11 }, 12 ... 13 }, 14 { 15 "$project": { 16 "paginationToken" : { "$meta" : "searchSequenceToken" } 17 }, 18 ... 19 }]
输出
searchSequenceToken为结果中的每个文档生成一个基本64编码的词元。 令牌的长度随着查询的排序选项中指定的字段数量的增加而增加。 令牌不与数据库快照绑定。
除非在查询中指定 sort 选项,否则结果中的文档按默认顺序排序。要学习;了解如何对结果进行排序,请参阅对MongoDB搜索结果进行排序。
特定参考点后的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" 11 } 12 }, 13 ... 14 }, 15 "$project": { 16 "paginationToken" : { "$meta" : "searchSequenceToken" } 17 }, 18 ... 19 }
输出
MongoDB Search 返回结果中指定词元之后的文档。MongoDB Search 在结果中返回为文档生成的词元,因为您在searchSequenceToken $project$search阶段之后的 阶段中指定了 (如第11 行所示)。这些词元可用作具有相同语义的另一个查询的参考点。
除非在查询中指定 sort 选项,否则结果中的文档按默认顺序排序。要学习;了解如何对结果进行排序,请参阅对MongoDB搜索结果进行排序。
特定参考点之前的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" 11 } 12 }, 13 ... 14 }, 15 "$project": { 16 "paginationToken" : { "$meta" : "searchSequenceToken" } 17 }, 18 ... 19 }
searchBefore 输出
MongoDB Search 以相反的顺序返回结果中指定词元之前的文档。MongoDB Search 还会在结果中返回为文档生成的词元,因为您在searchSequenceToken $project$search阶段之后的 阶段中指定了 (如第11 行所示)。这些词元可用作具有相同语义的另一个查询的参考点。
示例
以下示例使用 sample-mflix.movies集合,该集合具有名为 default 且具有动态映射的MongoDB搜索索引。如果加载集合并创建索引,则可以对该集合运行以下查询。
这些查询演示了如何检索参考点,然后在后续查询中使用该参考点检索指定参考点之前和之后同一术语的其他结果。
这些示例演示了如何执行以下任务:
注意
默认下, MongoDB Search 按文档的相关性分数对结果中的文档进行排序。如果结果中的多个文档具有相同分数, MongoDB 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 生成的令牌返回第一页的结果:
| |
将结果限制为 | |
仅包括结果中文档的
|
注意
默认下,对于指定标记以检索引用点之前结果的查询, MongoDB搜索会按相反顺序检索结果。要按顺序返回文档,查询使用 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 生成的令牌来指定要检索结果的参考点,然后跳过结果中的二十个文档。
示例查询使用以下管道阶段跳转到第 5 页上的结果,方法是使用 searchSequenceToken从同一术语的先前查询中生成的令牌,并使用 $skip 和 $limit 阶段:
| |
跳过指定参考点后结果中的 20 个文档,该参考点是您运行查询以使用 searchAfter 检索第 2 页的结果中与第 20 个文档关联的令牌。 | |
将结果限制为 | |
仅包括结果中文档的
|
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 } ]
要使用MongoDB Search facet(MongoDB Search Operator)对结果群组,您必须将任何 string字段索引为 token 类型。要运行以下查询并按 movies集合中的 genres字段对结果群组,您的索引必须类似于以下示例:
{ "mappings": { "dynamic": true, "fields": { "genres": { "type": "token" } } } } }
示例查询使用以下管道阶段:
| |
添加 | |
将结果限制为 | |
返回以下字段:
|
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') } ] } } } } ]