尝试使用 MongoDB 的官方 Rust 驱动程序(alpha 版)(2)(使用结构体)

概述

本次实现使用结构体进行插入和查找操作。同时,需要考虑当结构体的某些字段没有数据时的处理方式。

环境

    • Windows 10

 

    • MongoDB Community版 4.2.2

 

    • rust 1.40.0

 

    • MongoDB rust

ドライバー 0.9.0 (alpha版)

https://crates.io/crates/mongodb
https://github.com/mongodb/mongo-rust-driver

bson 0.14.0

https://crates.io/crates/bson
https://github.com/mongodb/bson-rust

Rustのクレートなど

serde 1.0.104

进行实施

向Cargo.toml中的dependencies部分添加

[dependencies]

mongodb ="0.9.0"
bson = "0.14.0"
serde = "1.0.104"

请用中文来解释这个词”コード”。

use mongodb::{error::Result, options::{ClientOptions}, Client};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Coll {
    pub item1: f64,
    pub item2: i64,
    pub item3: String 
}

fn main() {
    let client = connect_mongo().expect("failed to connect");
    insert_docs(&client).expect("failed to insert docs");
    find_all_docs(&client).expect("failed to find all docs");
}

fn connect_mongo() -> Result<Client> {
    let mut client_options = ClientOptions::parse("mongodb://localhost:27017")?;
    client_options.app_name = Some("My App".to_string());
    let client = Client::with_options(client_options)?;
    Ok(client)
}

fn insert_docs(client: &Client) -> Result<()> {
    let collection = client.database("test").collection("coll");
    let col_data = Coll{
        item1: 12.3,
        item2: 456,
        item3: String::from("string data")
    };
    let serialized_data = bson::to_bson(&col_data)?; 
    if let bson::Bson::Document(document) = serialized_data {
        collection.insert_one(document, None)?; 
    } else {
        println!("Error converting the BSON object into a MongoDB document");
    }
    Ok(())
}

fn find_all_docs(client: &Client) -> Result<()> {
    let collection = client.database("test").collection("coll");
    let cursor = collection.find(None, None)?;
    for result in cursor {
        match result {
            Ok(document) => {   
                let coll =  bson::from_bson::<Coll>(bson::Bson::Document(document))?;
                println!("item1: {}, item2: {}, item3: {}", coll.item1, coll.item2, coll.item3);
            }
            Err(e) => return Err(e.into()),
        }
    }
    Ok(())
}

構造体に値を代入するには、bson::from_bson::を使用しています。

cargo run
     Running `target\debug\mongorust.exe`
item1: 12.3, item2: 456, item3: string data

我会创建一些缺少字段的数据来测试。

mongo

> db.coll.insert({item1:11})
WriteResult({ "nInserted" : 1 })
> db.coll.find()
{ "_id" : ObjectId("5e2644d000a7d017003530ee"), "item1" : 12.3, "item2" : NumberLong(456), "item3" : "string data" }
{ "_id" : ObjectId("5e264597469b580a90779fbe"), "item1" : 11 }

再次运行Rust程序

cargo run
     Running `target\debug\mongorust.exe`
item1: 12.3, item2: 456, item3: string data
thread 'main' panicked at 'failed to find all docs: Error { kind: BsonDecode(ExpectedField("item2")) }', src\libcore\result.rs:1165:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: process didn't exit successfully: `target\debug\mongorust.exe` (exit code: 101)

如果结构体的字段数据不存在,则会出现上述错误。因此,将结构体的数据类型设置为Option类型。另外,我们来看看在插入时插入None会发生什么。

use mongodb::{error::Result, options::{ClientOptions}, Client};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Coll {
    pub item1: f64,
    pub item2: Option<i64>,
    pub item3: Option<String>
}

fn main() {
    let client = connect_mongo().expect("failed to connect");
    insert_docs(&client).expect("failed to insert docs");
    find_all_docs(&client).expect("failed to find all docs");
}

fn connect_mongo() -> Result<Client> {
    let mut client_options = ClientOptions::parse("mongodb://localhost:27017")?;
    client_options.app_name = Some("My App".to_string());
    let client = Client::with_options(client_options)?;
    Ok(client)
}

fn insert_docs(client: &Client) -> Result<()> {
    let collection = client.database("test").collection("coll");
    let col_data = Coll{
        item1: 78.9,
        item2: None,
        item3: Some(String::from("string data2"))
    };
    let serialized_data = bson::to_bson(&col_data)?; 
    if let bson::Bson::Document(document) = serialized_data {
        collection.insert_one(document, None)?; 
    } else {
        println!("Error converting the BSON object into a MongoDB document");
    }
    Ok(())
}

fn find_all_docs(client: &Client) -> Result<()> {
    let collection = client.database("test").collection("coll");
    let cursor = collection.find(None, None)?;
    for result in cursor {
        match result {
            Ok(document) => {   
                let coll =  bson::from_bson::<Coll>(bson::Bson::Document(document))?;
                print!("item1: {}", coll.item1);
                match coll.item2 {
                    Some(v) => print!(" item2: {}", v),
                    None => {}
                }
                match coll.item3 {
                    Some(v) => print!(" item3: {}", v), 
                    None => {}
                }
                println!()
            }
            Err(e) => return Err(e.into()),
        }
    }
    Ok(())
}

我使用None将item2插入了。
我使用了一个条件,在find中当结构体的每个字段为None时不打印。除了使用match来操作每个字段,我想不到其他的方法。

cargo run
     Running `target\debug\mongorust.exe`
item1: 12.3 item2: 456 item3: string data
item1: 11
item1: 78.9 item3: string data2

由于意图之外的字段是空的,所以它没有被打印出来。
接下来我们将在Mongo中进行确认。

mongo
> db.coll.find()
{ "_id" : ObjectId("5e2644d000a7d017003530ee"), "item1" : 12.3, "item2" : NumberLong(456), "item3" : "string data" }
{ "_id" : ObjectId("5e264597469b580a90779fbe"), "item1" : 11 }
{ "_id" : ObjectId("5e269159008ba689009e7150"), "item1" : 78.9, "item2" : null, "item3" : "string data2" }

在 Rust 中,因为使用了 None 插入,导致字段的值变成了 null。目前还不清楚有没有方法可以不插入结构体中已定义的字段。

最后

我对Rust中的错误处理和枚举不太理解,无法解释代码中的一些部分。
对于MongoDB的CRUD,aggregate、update、delete等功能还没有完全掌握,但似乎并不太难。然而,我还没找到事务功能。

链接

试用 MongoDB 官方 Rust 驱动程序(Alpha 版)。