使用游标访问数据
概述
在本指南中,您可以了解如何使用 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()
方法返回对游标中当前结果的引用,并将结果反序列化为与游标关联的类型。 除非指定类型,否则该方法将使用对collection进行参数化时使用的同一类型。
重要
仅当advance()
方法返回true
结果时,才能调用deserialize_current()
方法。 如果您在游标上调用deserialize_current()
没有true
结果,或者没有调用之前调用的advance()
,则驱动程序会生成错误。
以下示例展示了如何实现此访问模式以遍历collection上查找操作的结果:fruits
let mut cursor = my_coll.find(doc! { "color": "red" }, None).await?; while cursor.advance().await? { println!("{:?}", cursor.deserialize_current()?); }
流实现模式
您可以以流的形式访问游标结果,以检索单个文档或一次收集多个文档。
Cursor
类型实现了Stream
特征,因此您可以将游标作为流进行迭代。 与内置模式相比,此模式可帮助您编写更简洁的代码,因为Stream
扩展特征StreamExt
提供了许多用于组合操作和整合代码的函数。
您可以通过以下方法来使用流模式:
next()
:将游标前进到下一个结果并返回Option<Result<T>>
类型try_next()
:将游标前进到下一个结果并返回Result<Option<T>>
类型
重要
流模式方法所需的导入
要使用next()
方法,您必须导入StreamExt
特征。 要使用try_next()
方法,您必须导入TryStreamExt
特征。
fruits
以下示例展示了如何实现两个流方法以遍历collection上的查找操作结果:
let mut cursor = my_coll.find(doc! { "color": "red" }, None).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" }, None).await?; println!("Output from try_next() iteration:"); while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
以数组形式检索文档
由于Cursor
类型实现了Stream
特征,因此您可以将游标的结果收集到数组中。
您可以使用以下方法以数组形式检索文档:
collect()
:将游标的结果收集为Vec<Result<T>>
类型try_collect()
:将游标的结果收集为Result<Vec<T>>
类型
注意
要使用collect()
方法,您必须导入StreamExt
特征。 要使用try_collect()
方法,您必须导入TryStreamExt
特征。
let cursor = my_coll.find(doc! { "color": "red" }, None).await?; println!("Output from collect():"); let v: Vec<Result<Fruit>> = cursor.collect().await; println!("{:?}", v); println!(); let cursor = my_coll.find(doc! { "color": "yellow" }, None).await?; println!("Output from try_collect():"); let v: Vec<Fruit> = cursor.try_collect().await?; println!("{:?}", v);
警告
避免超出应用程序内存限制
避免将大量结果转换为数组。如果数组超过可用应用程序内存大小,应用程序可能会崩溃。如果需要较大的结果集,请分别从游标中检索文档。要了解如何遍历游标,请参阅本指南的单独检索文档部分。
指定游标行为
要修改操作返回的游标,请将选项传递给返回Cursor
实例的方法。 例如,您可以在传递给find()
方法的FindOptions
类型中指定与游标相关的选项。
注意
实例化选项
Rust 驱动程序实现了用于创建许多不同类型的 Builder 设计模式,包括FindOptions
。 您可以使用每种类型的builder()
方法,通过逐个链接选项构建器函数来构造选项实例。
下表描述了您可以在选项实例中设置的与游标相关的选项:
设置 | 说明 |
---|---|
batch_size | 指定服务器在每个游标批处理中返回的最大文档数。 此选项设置游标在内存中保留的文档数,而不是游标返回的文档数。 类型: u32 默认:最初有 101 个文档,后续批处理的最大数量为16 MB |
cursor_type | |
no_cursor_timeout |
以下代码展示了如何构造FindOptions
实例并指定与游标相关的设置:
let opts: FindOptions = FindOptions::builder() .batch_size(5) .cursor_type(CursorType::Tailable) .no_cursor_timeout(true) .build();
更多信息
要了解有关本指南中操作的更多信息,请参阅以下文档:
要了解有关 Rust 类型和 BSON 之间转换的更多信息,请参阅数据建模和序列化指南。
API 文档
要进一步了解本指南所提及的方法和类型,请参阅以下 API 文档:
next() 在
StreamExt
特征中try_next() 在
TryStreamExt
特征中collect() 在
StreamExt
特征中try_collect() 在
TryStreamExt
特征中