Generic MongoDB function in Rust
Tags: rust, programming, development, backend
Published: 2022-11-13 08:46:18

Hello guys!. As an Android Developer 🤖❤️, I find myself learning Rust and it seems more and more entertaining to play in my spare time with this language. Today I want to write a bit and this time we will create a small utility to work with MongoDB cursors in Rust in a generic way.

While having fun with Rust and doing a couple of queries with MongoDB I realized that I was repeating the same pattern in different places: a listing of N things that follow an identical query structure in MongoDB. Giving a little more context, when we want to retrieve a set of data from a Mongo collection, we get a cursor of the type of data we want. Based on that scenario, I wanted to create a small function that would help me convert that cursor to an array of data of type T, where T is a generic type; that is, when calling my function T, it will take the specific type that it needs at that moment.
<br />

### Generic Data Types
>We use generics to create definitions for items like function signatures or structs, which we can then use with many different concrete data types.

_you can see more about the generic data types [here](https://doc.rust-lang.org/book/ch10-01-syntax.html)._
<br />


### Let’s get to the point
First of all, I want to start from the fact that it is not a tutorial that starts from scratch, I am assuming that you know and understand the most basic concepts of Rust such as: how to create a project, functions and modules in Rust, among other small concepts . Having said all of the above, let’s continue with the article.

We’ll start by defining our generic function that will receive a generic cursor `Cursor::<T>` and return a data set `Vec<T>`. To define our generic function we will create a module mod.rs (You name it to your liking). For this example we will call our function `extract_data` and add the code below.

```rust
use mongodb::Cursor;
use futures::stream::StreamExt;
use rocket::serde::DeserializeOwned;

pub async fn extract_data<T: DeserializeOwned + Unpin + Send + Sync>(mut cursor: Cursor::<T>) -> Vec<T> {
    let mut result = Vec::new();
    while let Some(doc) = cursor.next().await {
        let item = doc.unwrap();
        result.push(item)
    }
    result
}
```

Let’s create a small function to get a list of users. Don’t focus on the content of the function; surely you can make better code. We will call this function `get_users_cursor`.

```rust
async fn get_users_cursor() -> Cursor<UserModel> {
  let mut client_options = ClientOptions::parse(DATABASE_URI)?;
  client_options.app_name = Some(APP_NAME.to_string());
  let client = Client::with_options(client_options)?;
  let database = client.database(DATABASE_NAME);

  let collection: Collection<UserModel> = client.database(DATABASE_NAME)
    .collection::<UserModel>("users");

  collection.find(None, None).await.unwrap()
}
```

Finally, it’s time to call our generic function to obtain a dataset of the generic type, which in our example is `UserModel`.

```rust
pub async fn fetch_detail(&self) -> Vec<UserModel> {
  let cursor = self.get_users_cursor().await;
  extract_data::<UserModel>(cursor).await
}
```

Remember to import the module path where you defined the `extract_data` generic function.
<br />



If you like my content and want to support my work, you can give me a cup of coffee ☕️ 🥰

[![Ko-fi](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j18vjijbegi1dhp83ozv.png)](https://ko-fi.com/devjorgecastro)

[![Buy me a coffee](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdz714gpdbxv6ve001hf.png)](https://www.buymeacoffee.com/jorgecastro)


### Follow me in
Twitter: [@devjcastro](https://twitter.com/devjcastro)
<br />