Daniel
Daniel

Reputation: 221

How to get collection of document from mongodb cursor?

I have the following code which should return a list of documents from mongodb.

struct Vehicle{
    id: String,
    name: String
}

pub async fn list_all() -> Vec<Vehicle>{
    let mongodb = connection_bd::connection_mongodb().await;
    let mongodb_collection = mongodb.collection("Vehicle");
    let result = mongodb_collection.find(None, None).await; //result: Result<Cursor<Document>, Error>
    let cursor = match result { //cursor: Cursor<Document>
        Ok(x) => x,
        Err(_) => return vec![]
    };
    //...
}

I can't finish the code because I don't know how to convert Cursor<Document> to Vec<T>, it's my first time seeing Cursor<Document> and I don't know what it is.

Updated
Error message:

error[E0308]: mismatched types
  --> src\vehicle_repo.rs:77:40
   |
77 |   pub async fn list_all() -> Vec<Vehicle>{
   |  ________________________________________^
78 | |     let mongodb = connection_bd::connection_mongodb().await;
79 | |     let mongodb_collection = mongodb.collection("Vehicle");
...  |
84 | |     };
85 | | }
   | |_^ expected struct `Vec`, found `()`
   |
   = note: expected struct `Vec<Vehicle>`
           found unit type `()`

Upvotes: 4

Views: 5642

Answers (1)

kmdreko
kmdreko

Reputation: 60497

A mongodb Cursor implements Stream from the futures crate. This is mentioned in the docs:

Additionally, all the other methods that a Stream has are available on Cursor as well. This includes all of the functionality provided by StreamExt, which provides similar functionality to the standard library Iterator trait. For instance, if the number of results from a query is known to be small, it might make sense to collect them into a vector:

let results: Vec<Result<Document>> = cursor.collect().await;

I would actually recommend using the try_collect() function from the TryStreamExt trait to get a Result<Vec<Document>> instead. Then you can use unwrap_or_else() to return the list. You should also use the collection_with_type() method to get the collection so that your results will be automatically deserialized to the proper type instead of just Document (just make sure it implements Debug, Serialize and Deserialize).

Here's a working sample

use futures::TryStreamExt;
use mongodb::Client;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Vehicle {
    id: String,
    name: String,
}

async fn list_all() -> Vec<Vehicle> {
    let client = Client::with_uri_str("mongodb://example.com").await.unwrap();
    let database = client.database("test");
    let collection = database.collection_with_type::<Vehicle>("vehicles");
    let cursor = match collection.find(None, None).await {
        Ok(cursor) => cursor,
        Err(_) => return vec![],
    };

    cursor.try_collect().await.unwrap_or_else(|_| vec![])
}

Upvotes: 5

Related Questions