使用游标访问数据
概述
在本指南中,您可以学习如何使用Rust驱动程序,通过使用游标来访问读取操作或聚合操作返回的数据。游标是一种机制,允许您在给定时间内只将部分文档保留在内存中,同时遍历多个文档。
驱动程序提供了Cursor
类型来从游标中检索文档。例如,当您运行可以返回多个文档的查找操作时,驱动程序返回一个Cursor
实例,您可以通过该实例访问匹配的文档。
运行读取操作或聚合操作后,返回的Cursor
实例包含操作的第一批结果。随着您遍历游标,服务器返回更多的单个结果。如果在达到一批结果结束时还有更多匹配的文档,则Cursor
实例将检索下一批文档,直到所有结果返回。
本指南包括以下部分
示例数据
本指南中的示例使用以下存储在结构体中的数据
let docs = vec! [ Fruit { name: "strawberry".to_string(), color: "red".to_string() }, Fruit { name: "banana".to_string(), color: "yellow".to_string() }, Fruit { name: "pomegranate".to_string(), color: "red".to_string() }, Fruit { name: "pineapple".to_string(), color: "yellow".to_string() } ];
逐个检索文档
驱动程序提供了以下访问模式来遍历由Cursor
实例返回的文档
以下章节将更详细地描述这些访问模式和相应的方法。
内置模式
您可以使用驱动程序的内置访问模式逐个检索和处理文档。
Cursor
类型包括advance()
和deserialize_current()
方法,用于遍历游标并逐个访问文档。
advance()
方法将光标向前移动,并在本地缓冲区耗尽时向数据库发送请求以获取更多结果,这发生在光标到达结果批次末尾时。每次光标到达结果批次末尾时,都会请求下一批次。当光标没有更多匹配的文档返回并且不再可用时,光标就会耗尽。如果成功返回新结果,则 advance()
方法返回一个 true
结果,如果光标被关闭,则返回一个 false
结果。
deserialize_current()
方法返回光标中当前结果的引用,并将结果反序列化为与光标关联的类型。除非您指定类型,否则该方法将使用与您的集合参数化相同的类型。
重要
只有在 advance()
方法返回一个 true
结果的情况下,才能调用 deserialize_current()
方法。如果您在没有 true
结果或未先调用 advance()
的情况下对光标调用 deserialize_current()
,则驱动程序将生成错误。
以下示例展示了如何实现此访问模式以遍历对 fruits
集合的查找操作的结果。
let mut cursor = my_coll.find(doc! { "color": "red" }).await?; while cursor.advance().await? { println!("{:?}", cursor.deserialize_current()?); }
Fruit { name: "strawberry", color: "red" } Fruit { name: "pomegranate", color: "red" }
流实现模式
您可以将光标结果作为流来检索单个文档或一次收集多个文档。
Cursor
类型实现了 Stream
特性,因此您可以将光标作为流来迭代。您可以使用此模式来编写比内置模式更简洁的代码,因为 Stream
扩展特性 StreamExt
提供了众多函数来组合操作和简化代码。
您可以使用以下方法使用流模式
next()
:将光标移动到下一个结果并返回一个Option<Result<T>>
类型try_next()
:将光标移动到下一个结果并返回一个Result<Option<T>>
类型
重要
Stream 模式方法所需导入
要使用 next()
方法,您必须导入 StreamExt
特性。要使用 try_next()
方法,您必须导入 TryStreamExt
特性。
以下示例展示了如何实现这两个流方法以遍历对 fruits
集合的查找操作的结果。
let mut cursor = my_coll.find(doc! { "color": "red" }).await?; println!("Output from next() iteration:"); while let Some(doc) = cursor.next().await { println!("{:?}", doc?); } println!(); let mut cursor = my_coll.find(doc! { "color": "yellow" }).await?; println!("Output from try_next() iteration:"); while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Output from next() iteration: Fruit { name: "strawberry", color: "red" } Fruit { name: "pomegranate", color: "red" } Output from try_next() iteration: Fruit { name: "banana", color: "yellow" } Fruit { name: "pineapple", color: "yellow" }
将文档作为数组检索
因为Cursor
类型实现了Stream
特质,所以可以将游标的结果收集到一个数组中。
您可以使用以下方法将文档作为数组检索:
collect()
:将游标的结果收集到Vec<Result<T>>
类型中try_collect()
:将游标的结果收集到Result<Vec<T>>
类型中
注意
要使用collect()
方法,您必须导入StreamExt
特质。要使用try_collect()
方法,您必须导入TryStreamExt
特质。
let cursor = my_coll.find(doc! { "color": "red" }).await?; println!("Output from collect():"); let v: Vec<Result<Fruit>> = cursor.collect().await; println!("{:?}", v); println!(); let cursor = my_coll.find(doc! { "color": "yellow" }).await?; println!("Output from try_collect():"); let v: Vec<Fruit> = cursor.try_collect().await?; println!("{:?}", v);
Output from collect(): [Ok(Fruit { name: "strawberry", color: "red" }), Ok(Fruit { name: "pomegranate", color: "red" })] Output from try_collect(): [Fruit { name: "banana", color: "yellow" }, Fruit { name: "pineapple", color: "yellow" }]
警告
避免超出应用程序内存限制
避免将大量结果转换为数组。如果数组大小超过可用应用程序内存,则您的应用程序可能会崩溃。如果您预计结果集很大,请逐个检索文档。有关如何遍历游标的说明,请参阅本指南的逐个检索文档部分。
指定游标行为
要修改操作返回的游标,请将选项构建器方法链接到返回Cursor
实例的方法。例如,可以将与游标相关的选项构建器方法链接到find()
方法。
注意
设置选项
您可以直接将选项构建器方法链接到 find()
方法调用来设置 FindOptions
字段。如果您正在使用更早版本的驱动程序,您必须通过将选项构建器方法链接到 builder()
方法来构造一个 FindOptions
实例。然后,将您的 FindOptions
实例作为参数传递给 find()
。
以下表格描述了您可以通过调用其相应的构建器方法设置的与游标相关的选项
设置 | 描述 |
---|---|
batch_size | 指定服务器每次游标批处理返回的最大文档数。此选项设置游标在内存中保留的文档数,而不是游标返回的文档数。 类型: u32 默认值: 初始时为 101 个文档,后续批次最大为 16 MB |
cursor_type | 指定要返回的游标类型。您可以设置此选项以生成可尾随的游标。有关可尾随游标的更多信息,请参阅服务器手册中的 可尾随游标。 类型: CursorType 默认值: CursorType::NonTailable |
no_cursor_timeout | 指定服务器是否在一段时间的不活动后关闭游标。 重要:由于 Cursor 类型实现了 Drop 特性,当游标超出作用域时,服务器会关闭游标。服务器运行异步的 killCursors 命令来关闭游标。有关更多信息,请参阅服务器手册中的 killCursors。类型: bool 默认值: false |
以下代码显示了如何通过将选项构建器方法链接到 find()
方法来指定游标相关的设置
let mut cursor = my_coll.find(doc! { "color": "red" }) .batch_size(5) .cursor_type(CursorType::Tailable) .no_cursor_timeout(true) .await?;
更多信息
有关本指南中操作的更多信息,请参阅以下文档
有关更多关于在 Rust 类型和BSON 之间转换的信息,请参阅有关 数据建模和序列化 的指南。
API 文档
要了解更多关于本指南中提到的方法和类型,请参阅以下 API 文档
next()在
StreamExt
接口中try_next()在
TryStreamExt
接口中collect() 在
StreamExt
接口中try_collect() 在
TryStreamExt
接口中