Rust driver: help writing a generic find method

Hi,

I am trying to write generic CRUD functions on structs that modelate my data.
I have the following code right now.

use futures::{TryStream, TryStreamExt};
    use anyhow::Result;
    use mongodb::results::InsertOneResult;
    use mongodb::{Database, bson::document::Document, options::FindOptions};
    use serde::{Deserialize, Serialize};

    pub trait MongoDbModel {
        fn collection_name() -> String;
    }

    pub async fn get_all_vec<I: MongoDbModel>(db: &Database, filter: Option<Document>, options: Option<FindOptions>) -> Vec<I> {
        let col = db.collection::<I>(&I::collection_name());
        let mut cursor = match col.find(None, None).await {
            Ok(cursor) => cursor,
            Err(_) => return vec![],
        };
    
        let mut documents: Vec<I> = Vec::new();
        while let Ok(Some(doc)) = cursor.try_next().await {
            documents.push(doc);
        }
    
        documents
    }

Trying to compile this results in

error[E0599]: the method `try_next` exists for struct `mongodb::Cursor<I>`, but its trait bounds were not satisfied
  --> src/lib/mongodb_client.rs:39:42
   |
39 |         while let Ok(Some(doc)) = cursor.try_next().await {
   |                                                                 ^^^^^ method cannot be called on `mongodb::Cursor<I>` due to unsatisfied trait bounds
   |
  ::: /Users/r/.cargo/registry/src/github.com-1ecc6299db9ec823/mongodb-2.2.2/src/cursor/mod.rs:94:1
   |
94 | pub struct Cursor<T> {
   | --------------------
   | |
   | doesn't satisfy `mongodb::Cursor<I>: TryStreamExt`
   | doesn't satisfy `mongodb::Cursor<I>: TryStream`
   |
   = note: the following trait bounds were not satisfied:
           `mongodb::Cursor<I>: TryStream`
           which is required by `mongodb::Cursor<I>: TryStreamExt`

warning: unused import: `TryStreamExt`
  --> src/lib/mongodb_client.rs:12:30
   |
12 |     use futures::{TryStream, TryStreamExt};
   |                              ^^^^^^^^^^^^

As you can see I’m importing futures::TryStreamExt and still this does not seem to be making use of it.

Can someone help me with this?
Thanks in advance!

Hey @Raymundo_63313!

The reason you’re seeing an error here is that the Cursor<T> type only implements Stream if the T implements DeserializeOwned, Unpin, Send, and Sync. You can see this requirement here: Cursor in mongodb - Rust. In your example, the I type is only required to implement MongoDbModel though, so all the trait requirements aren’t satisfied.

To fix this, you can update your MongoDbModel trait to inherit from those traits:

trait MongoDbModel: DeserializeOwned + Sync + Send + Unpin { ... }

Or, you can update the constraints of the get_all_vec function:

pub async fn get_all_vec<I>(
    db: &Database,
    filter: Option<Document>,
    options: Option<FindOptions>,
) -> Vec<I>
where
    I: MongoDbModel + DeserializeOwned + Unpin + Send + Sync,
{
    // impl here
}

As a side note, it may be possible for us to relax some of these trait requirements in a future version. I filed https://jira.mongodb.org/browse/RUST-1358 to track the work for investigating this. Thanks for bringing this to our attention!

1 Like

Thank you @Patrick_Freed! I took the approach of the boundaries in the function.

Besides solving the issue it has helped me to improve in Rust :slight_smile:

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.