MongoDB Rust: Projections with typed collections | How to do this?

Viewed 342

I am pretty new to Rust and just trying to learn it while coding a GraphQL API using MongoDB. Currently, I am struggling with decoding a document into my CourseDocument struct.

#[derive(Serialize, Deserialize, Debug, Eq)]
struct CourseDocument {
    #[serde(rename = "_id")]
    id: ObjectId,
    #[serde(rename = "localizedFields")]
    localized_fields: Vec<CourseDocumentLocalizedFields>,
    categories: Vec<ObjectId>,
    tags: Vec<ObjectId>,
    trainers: Vec<ObjectId>,
    videos: Vec<ObjectId>,
}

impl PartialEq for CourseDocument {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

In my main() function I tried the following

let course_collection = database.collection::<CourseDocument>("courses");

let projection = doc! {"localizedFields": 1};

let options = FindOptions::builder()
    .limit(10)
    .projection(projection)
    .build();

let mut cursor = course_collection.find(None, options).await.unwrap();

while let Some(course) = cursor.try_next().await.unwrap() {
    println!("{:#?}", course)
}

This code throws the following error: Error { kind: InvalidResponse { message: "missing field 'categories'" }, labels: {} }

The error does make sense because the CourseDocument requires the categories field to be at least an empty vector. But I am still wondering what would be the correct struct declaration.

Do I have to wrap every field with an Option enum to make projections and typed documents possible?

1 Answers

You can use clone_with_type() to make a Collection with the same source but with a different type. Using that, you can deserialize into a type with only those projected fields.

#[derive(Serialize, Deserialize)]
struct ProjectedCourseDocument {
    #[serde(rename = "localizedFields")]
    localized_fields: Vec<CourseDocumentLocalizedFields>,
}
let mut cursor = course_collection
    .clone_with_type::<ProjectedCourseDocument>()
    .find(None, options)
    .await
    .unwrap();
Related