使用 Azure Cosmos DB for MongoDB vCore 生成 Rust 控制台应用

本指南创建一个 Rust 控制台应用程序,用于连接到 Azure Cosmos DB for MongoDB vCore 群集。 本指南介绍了如何设置开发环境,使用 Azure SDK for Rust 中的 azure_identity crate 进行身份验证,以及管理数据库中的文档。

先决条件

  • 现有的 Azure Cosmos DB for MongoDB (vCore) 群集。
  • 为群集配置了 Microsoft Entra 身份验证,已授予标识 dbOwner 角色。

  • 最新版本的 Python

配置控制台应用程序

接下来,创建新的控制台应用程序项目,并导入必要的库以向群集进行身份验证。

  1. 使用 cargo new.. 创建新的 Rust 项目。

    cargo new cosmos-mongodb-app
    cd cosmos-mongodb-app
    
  2. azure_core Crate 添加到依赖项。

    cargo add azure_core
    
  3. 添加 azure_identity Crate 进行身份验证。

    cargo add azure_identity
    
  4. 添加 mongodb 驱动程序 Crate 以与群集交互。

    cargo add mongodb
    
  5. 对于异步操作,还要添加支持 tokiofuturesserde Crate。

    cargo add tokio --features full
    cargo add futures
    cargo add serde --features derive
    

连接至群集

现在,使用 Azure.Identity 库获取一个 TokenCredential,以用于连接到您的群集。 官方 MongoDB 驱动程序具有一个特殊接口,必须实现该接口,以便从 Microsoft Entra 获取令牌,以便在连接到群集时使用。

  1. 打开 main.rs 文件并导入必要的 Crate 和模块。

    use azure_core::credentials::TokenCredential;
    use azure_identity::DefaultAzureCredential;
    use futures::{FutureExt, TryStreamExt};
    use mongodb::{
        Client,
        bson::doc,
        options::{
            AuthMechanism, ClientOptions, Credential,
            oidc::{self, IdpServerResponse},
        },
    };
    use serde::{Deserialize, Serialize};
    
  2. 创建主异步函数,并进行必要的错误处理。

    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
    
        Ok(())
    }
    
  3. 创建结构 azure_identity::DefaultAzureCredential的新实例。

    let credential = DefaultAzureCredential::new()?;
    
  4. 创建凭据回调以处理来自 MongoDB 客户端的令牌请求。

    let azure_identity_token_credential = Credential::builder()
        .mechanism(AuthMechanism::MongoDbOidc)
        .oidc_callback(oidc::Callback::machine(move |_| {
            let azure_credential = credential.clone();
            async move {
                let access_token = azure_credential
                    .get_token(&["https://ossrdbms-aad.database.chinacloudapi.cn/.default"])
                    .await
                    .map_err(|e| {
                        mongodb::error::Error::custom(format!("Azure token error: {}", e))
                    })?;
                Ok(IdpServerResponse::builder()
                    .access_token(access_token.token.secret().to_owned())
                    .build())
            }
            .boxed()
        }))
        .build()
        .into();
    
  5. 使用群集的名称、方案和全局终结点定义统一的资源指示器(URI)。

    let cluster_name = "<azure-cosmos-db-mongodb-vcore-cluster-name>";
    
    let uri = format!(
        "mongodb+srv://{}.global.mongocluster.cosmos.azure.com/",
        cluster_name
    );
    
  6. 使用最佳实践配置、您的 URI 和凭据回调来构造 mongodb::ClientOptions 实例。

    let mut client_options = ClientOptions::parse(uri).await?;
    
    client_options.connect_timeout = Some(std::time::Duration::from_secs(120));
    client_options.tls = Some(mongodb::options::Tls::Enabled(Default::default()));
    client_options.retry_writes = Some(true);
    
    client_options.credential = Some(azure_identity_token_credential);
    
  7. 创建使用已构造设置的新实例 mongodb::Client

    let client = Client::with_options(client_options)?;
    
    println!("Client created");
    

执行常见操作

最后,使用官方库对数据库、集合和文档执行常见任务。 在这里,你将使用相同的类和方法与 MongoDB 或 DocumentDB 进行交互来管理集合和项。

  1. 创建一个 Rust 结构,用于表示支持 Product 序列化的 serde 文档。

    #[derive(Serialize, Deserialize, Debug)]
    struct Product {
        _id: String,
        category: String,
        name: String,
        quantity: i32,
        price: f64,
        clearance: bool,
    }
    
  2. 按名称获取对数据库的引用。

    let database = client.database("<database-name>");
    
    println!("Database pointer created");
    
  3. 获取对集合的引用。

    let collection = database.collection::<Product>("<collection-name>");
    
    println!("Collection pointer created");
    
  4. 使用 collection.update_one 创建文档,并将其更新插入到集合中。

    let document = Product {
        _id: "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb".to_string(),
        category: "gear-surf-surfboards".to_string(),
        name: "Yamba Surfboard".to_string(),
        quantity: 12,
        price: 850.00,
        clearance: false,
    };
    
    let response = collection
        .update_one(
            doc! { "_id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" },
            doc! { "$set": mongodb::bson::to_document(&document)? },
        )
        .upsert(true)
        .await?;
    
    println!("Documents upserted count:\t{}", response.modified_count);
    
  5. 使用 collection.find_one 筛选器从集合中读取特定文档。

    let document = collection
        .find_one(doc! { "_id": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" })
        .await?;
    
    println!("Read document _id:\t{:#?}", document.unwrap()._id);
    
  6. 使用 collection.find 查询匹配筛选条件的多个文档。

    let filter = doc! { "category": "gear-surf-surfboards" };
    
    let mut cursor = collection.find(filter).await?;
    
    while let Some(document) = cursor.try_next().await? {
        println!("Found document:\t{:#?}", document);
    }
    
注意:作者在 AI 的帮助下创作了此文章。 了解详细信息