Search code examples
mongodbrustrust-tokio

How can I get a field value from a document?


I’m trying to get the value of a specific field in the document when searching for it like:

use mongodb::{bson::{doc,Document},options::ClientOptions, Client};
//..
let client = Client::with_options(ClientOptions::parse("mongodb+srv://user:pass@cluster0.um0c2p7.mongodb.net/?retryWrites=true&w=majority").await.unwrap()).unwrap();
let coll = client.database("braq").collection("users");
let user  = coll.find_one(doc!{"user":"user1"},None).await.unwrap();
println!("Hello, {}!",user.user1);

The error I get:

#9 311.1 error[E0698]: type inside `async fn` body must be known in this context
#9 311.1   --> src/main.rs:46:35
#9 311.1 46 |     let db = client.database("braq").collection("users");
#9 311.1    |                                      ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `collection`
#9 311.1 note: the type is part of the `async fn` body because of this `await`
#9 311.1   --> src/main.rs:47:50
#9 311.1 47 |     let deb  = db.find_one(doc!{"user":"user1"},None).await.unwrap();
#9 311.1    |                                                     ^^^^^^
#9 311.1 
------
 > [4/4] RUN cargo install --path .:
#9 311.1 46 |     let db = client.database("braq").collection("users");
#9 311.1    |                                      ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `collection`
#9 311.1 note: the type is part of the `async fn` body because of this `await`
#9 311.1   --> src/main.rs:47:50
#9 311.1 47 |     let deb  = db.find_one(doc{"user":"user1"},None).await.unwrap();
#9 311.1    |                                                     ^^^^^^

How can I do that without errors?


Solution

  • The error message you get is because you don't provide a generic type to your collection. Read more about it here.

    If you want to work with bson::Document (which your title suggests; it is also the most generic type your collection can have, allowing you to store and retrieve arbitrary documents without any restrictions beyond those imposed by mongodb itself), you have to use one of the many get methods it offers. If you expect the field user1 to be a string, you could use the Document::get_str method, for example:

    let coll = client.database("braq").collection::<Document>("users");
                                                 // ^^^^^^^^ type of our collection 
    let user: Document = coll.find_one(doc! {"user":"user1"}, None).await.unwrap().unwrap();
        
    println!("Hello, {}!", user.get_str("user1").unwrap());
    

    Alternatively, you can also tell your collection what concrete Rust type the documents it stores are made from and it will take care of de-serialising the query result into your Rust type. The only restriction is that your type must implement serde's Deserialize trait:

    use serde::Deserialize;
        
    #[derive(Deserialize)]
    struct User {
        user1: String,
    }
        
    let coll = client.database("braq").collection::<User>("users");
                                                 // ^^^^ type of our collection
    let user: User = coll.find_one(doc! {"user":"user1"}, None).await.unwrap().unwrap();
        
    println!("Hello, {}!", user.user1);