Overview
在本指南中,您可以了解如何使用读取操作从 MongoDB collection中检索数据。读取操作是从服务器检索文档的命令。
有两种类型的读取操作:
查找操作,允许您从collection中检索文档
聚合操作,允许转换collection中的数据
本指南包括以下部分:
示例样本数据
本指南中的几个示例使用了以下示例文档。每个文档代表存储库存中的一个商品,并包含有关其分类和单价的信息:
let docs = vec![ Inventory { item: "candle".to_string(), category: "decor".to_string(), unit_price: 2.89, }, Inventory { item: "blender".to_string(), category: "kitchen".to_string(), unit_price: 38.49, }, Inventory { item: "placemat".to_string(), category: "kitchen".to_string(), unit_price: 3.19, }, Inventory { item: "watering can".to_string(), category: "garden".to_string(), unit_price: 11.99, }, ];
查找操作
使用查找操作从 MongoDB 检索数据。 查找操作由find()和find_one()方法组成。
查找所有匹配文档
要查找所有符合条件的文档,请使用find()方法。 此方法将查询筛选器作为参数。 查询筛选器由构成要匹配的文档条件的字段和值组成。
该方法返回一个Cursor类型,您可以遍历该类型以检索与过滤条件匹配的任何文档。
要查看使用此方法检索数据的示例,请参阅find() 示例。
要了解有关指定查询的更多信息,请参阅指定查询指南。
查找一个文档
要查找第一个符合条件的文档,请使用find_one()方法。 此方法将查询筛选器作为参数。 查询筛选器由构成要匹配的文档条件的字段和值组成。
如果文档与筛选条件匹配,该方法将返回值为Some的Result<Option<T>>类型。 如果没有符合筛选条件的文档, find_one()将返回值为None的Result<Option<T>>类型。
要查看使用此方法检索数据的示例,请参阅find_one()示例。
修改查找行为
您可以通过将FindOptions选项构建器方法链接到find()来修改find()方法的行为,也可以通过将FindOneOptions选项构建器方法链接到find_one()来修改find_one()方法的行为。
下表描述了常用的FindOptions和FindOneOptions字段,您可以通过调用相应的构建器方法来设立这两个字段:
字段 | 说明 |
|---|---|
| |
| |
| |
| |
| 返回结果时要跳过的文档数。要详细学习;了解如何使用 |
|
注意
设置选项
您可以通过将选项构建者方法直接链接到查找操作方法调用设立FindOptions 和 FindOneOptions 字段。如果使用的是早期版本的驱动程序,则必须通过将选项构建器方法链接到 builder() 方法来构造 FindOptions 或 FindOneOptions实例。然后,将选项实例作为参数传递给 find() 或 find_one()。
有关可以为每种类型指定的设置的完整列表,请参阅 FindOptions 和 FindOneOptions 的API文档。
查找示例
以下部分包含使用find()和find_one()方法检索与过滤条件匹配的样本文档的示例。
find() 示例
此示例将执行以下动作:
调用
find()方法将查询过滤传递给
find(),用于匹配unit_price值小于12.00且category值不为"kitchen"的文档将
sort()方法链接到find(),以按unit_price降序对匹配的文档进行排序
let mut cursor = my_coll .find(doc! { "$and": vec! [ doc! { "unit_price": doc! { "$lt": 12.00 } }, doc! { "category": doc! { "$ne": "kitchen" } } ] }) .sort(doc! { "unit_price": -1 }) .await?; while let Some(result) = cursor.try_next().await? { println!("{:?}", result); }
Inventory { item: "watering can", category: "garden", unit_price: 11.99 } Inventory { item: "candle", category: "decor", unit_price: 2.89 }
完整文件示例:查找文档
此示例从 sample_restaurants数据库的 restaurants集合中检索与查询过滤匹配的文档。 find() 方法会返回 cuisine字段的值为 "French" 的所有文档。
您可以将每个检索到的文档建模为 Document 类型或自定义数据类型。 要指定哪种数据类型表示集合的数据,请将突出显示的行上的 <T> 类型参数替换为以下值之一:
<Document>:检索集合文档并将其打印为BSON文档<Restaurant>:检索集合文档并将其打印为Restaurant结构的实例,该结构在代码顶部定义
选择Asynchronous或Synchronous标签页,查看每个运行时的相应代码:
use mongodb::{ bson::doc, Client, Collection }; use futures::TryStreamExt; use serde::{ Deserialize, Serialize }; struct Restaurant { name: String, cuisine: String, } async fn main() -> mongodb::error::Result<()> { let uri = "<connection string>"; let client = Client::with_uri_str(uri).await?; // Replace <T> with the <Document> or <Restaurant> type parameter let my_coll: Collection<T> = client .database("sample_restaurants") .collection("restaurants"); let mut cursor = my_coll.find( doc! { "cuisine": "French" } ).await?; while let Some(doc) = cursor.try_next().await? { println!("{:#?}", doc); } Ok(()) }
use mongodb::{ bson::doc, sync::{Client, Collection} }; use serde::{ Deserialize, Serialize }; struct Restaurant { name: String, cuisine: String, } fn main() -> mongodb::error::Result<()> { let uri = "<connection string>"; let client = Client::with_uri_str(uri)?; // Replace <T> with the <Document> or <Restaurant> type parameter let my_coll: Collection<T> = client .database("sample_restaurants") .collection("restaurants"); let mut cursor = my_coll.find( doc! { "cuisine": "French" } ).run()?; for result in cursor { println!("{:#?}", result?); } Ok(()) }
输出
选择 BSON Document Results 或 Restaurant Struct Results标签页,根据集合的类型参数查看相应的代码输出:
... Some( Document({ "_id": ObjectId( "...", ), ... "name": String( "Cafe Un Deux Trois", ), ... }), ), Some( Document({ "_id": ObjectId( "...", ), ... "name": String( "Calliope", ), ... }), ) ...
... Restaurant { name: "Cafe Un Deux Trois", cuisine: "French", } Restaurant { name: "Calliope", cuisine: "French", } ...
从文件加载查询示例
您可以将查询筛选条件存储在JSON文件中,并在运行时加载。这种方法允许您在Rust应用程序和外部工具(例如MongoDB Shell (mongosh))之间股票查询定义。
提示
Serde JSON依赖项
在从文件加载查询之前,请从项目根目录运行以下命令以添加 serde_json 依赖项:
cargo add serde_json
首先,创建一个包含查询筛选条件的JSON文件。以下示例query.json文件包含一个比较查询筛选条件,用于匹配 category字段值为 "kitchen" 的文档:
{ "category": "kitchen" }
要将此文件加载到Rust应用程序中,请使用 std::fs::read_to_string() 方法读取该文件。然后,调用 serde_json::from_str() 将JSON字符串解析为 Document实例。由于 Document 实现了 serde::Deserialize 特征,因此您可以直接从JSON字符串对其进行反序列化。
以下示例从 query.json文件读取查询筛选条件并将其传递给 find() 方法:
let json = std::fs::read_to_string("query.json") .expect("failed to read query.json"); let filter: Document = serde_json::from_str(&json) .expect("query.json contains invalid JSON"); let mut cursor = my_coll.find(filter).await?; while let Some(doc) = cursor.try_next().await? { println!("{:?}", doc); }
Inventory { item: "blender", category: "kitchen", unit_price: 38.49 } Inventory { item: "placemat", category: "kitchen", unit_price: 3.19 }
find_one() 示例
此示例将执行以下动作:
调用
find_one()方法将查询过滤传递给
find_one(),用于匹配unit_price值小于或等于20.00的文档将
skip()方法链接到find_one()以跳过前两个匹配的文档
let result = my_coll .find_one(doc! { "unit_price": doc! { "$lte": 20.00 } }) .skip(2) .await?; println!("{:#?}", result);
Some( Inventory { item: "watering can", category: "garden", unit_price: 11.99, }, )
完整文件示例:查找文档
此示例从 sample_restaurants数据库的 restaurants集合中检索与查询过滤匹配的文档。 find_one() 方法返回 name字段值为 "Tompkins Square Bagels" 的第一个文档。
您可以将检索到的文档建模为 Document 类型或自定义数据类型。 要指定哪种数据类型表示集合的数据,请将突出显示的行上的 <T> 类型参数替换为以下值之一:
<Document>:检索集合文档并将其打印为BSON文档<Restaurant>:检索集合文档并将其打印为Restaurant结构的实例,该结构在代码顶部定义
选择Asynchronous或Synchronous标签页,查看每个运行时的相应代码:
use mongodb::{ bson::doc, Client, Collection }; use serde::{ Deserialize, Serialize }; struct Restaurant { name: String, cuisine: String, } async fn main() -> mongodb::error::Result<()> { let uri = "<connection string>"; let client = Client::with_uri_str(uri).await?; // Replace <T> with the <Document> or <Restaurant> type parameter let my_coll: Collection<T> = client .database("sample_restaurants") .collection("restaurants"); let result = my_coll.find_one( doc! { "name": "Tompkins Square Bagels" } ).await?; println!("{:#?}", result); Ok(()) }
use mongodb::{ bson::doc, sync::{Client, Collection} }; use serde::{ Deserialize, Serialize }; struct Restaurant { name: String, cuisine: String, } fn main() -> mongodb::error::Result<()> { let uri = "<connection string>"; let client = Client::with_uri_str(uri)?; // Replace <T> with the <Document> or <Restaurant> type parameter let my_coll: Collection<T> = client .database("sample_restaurants") .collection("restaurants"); let result = my_coll.find_one( doc! { "name": "Tompkins Square Bagels" } ).run()?; println!("{:#?}", result); Ok(()) }
输出
选择 BSON Document Result 或 Restaurant Struct Result标签页,根据集合的类型参数查看相应的代码输出:
Some( Document({ "_id": ObjectId( "...", ), ... "name": String( "Tompkins Square Bagels", ), ... }), )
Some( Restaurant { name: "Tompkins Square Bagels", cuisine: "American", }, )
聚合操作
使用聚合操作从collection中检索和转换数据。您可以使用aggregate()方法执行聚合操作。
聚合文档数据
aggregate()方法将聚合管道作为参数。 聚合管道包括一个或多个指定如何转换数据的阶段。 阶段包括聚合操作符(以$为前缀)以及该操作符所需的任何参数。
要了解有关聚合的更多信息并查看聚合示例,请参阅聚合指南。
该方法以Cursor类型返回结果文档。 如果聚合管道不包含$match阶段,则管道会处理集合中的所有文档。
修改聚合行为
您可以通过将AggregateOptions选项构建器方法链接到aggregate()来修改aggregate()方法的行为。
下表描述了常用的AggregateOptions字段,您可以通过调用相应的构建器方法来设立这些字段:
字段 | 说明 |
|---|---|
| 允许写入临时文件。如果为 |
| 指定服务器在每个游标批处理返回的最大文档数。此选项设置游标在内存中保留的文档数,而不是游标返回的文档数。类型: |
| |
| |
| |
|
有关设置的完整列表,请参阅 AggregateOptions 的API文档。
例子
此示例演示如何使用包含以下阶段的管道调用aggregate()方法:
$group阶段,用于计算category字段的每个值的unit_price字段的平均值$sort阶段按avg_price升序对结果进行排序
let pipeline = vec![ doc! { "$group": doc! { "_id" : doc! {"category": "$category"} , "avg_price" : doc! { "$avg" : "$unit_price" } } }, doc! { "$sort": { "_id.avg_price" : 1 } }, ]; let mut cursor = my_coll.aggregate(pipeline).await?; while let Some(result) = cursor.try_next().await? { println!("{:?}", result); }
Document({"_id": Document({"category": String("decor")}), "avg_price": Double(2.890000104904175)}) Document({"_id": Document({"category": String("kitchen")}), "avg_price": Double(20.840000867843628)}) Document({"_id": Document({"category": String("garden")}), "avg_price": Double(11.989999771118164)})
更多信息
有关查找操作的可运行示例,请参阅以下用法示例:
要了解有关本指南中操作的更多信息,请参阅以下文档:
API 文档
要进一步了解本指南所提及的方法和类型,请参阅以下 API 文档: