Ввод возвращаемого типа после проекции mongodb

#mongodb #rust #graphql

Вопрос:

Я создаю распознаватель graphql в rust и извлекаю только поля из запроса graphql в своей базе данных mongodb. Однако Rust жалуется, что извлеченные данные, конечно, теперь не того же типа, что и указанный тип возврата. Как правильно сделать что-то подобное?

Я думаю , я мог бы это сделать #[serde(default)] , но это работает не совсем так, как ожидалось (я объясню позже).

 use async_graphql::*;
use serde::{Deserialize, Serialize};
use mongodb::{bson::doc, bson::oid::ObjectId, options::FindOptions, Collection};

#[derive(SimpleObject, Serialize, Deserialize, Debug)]
#[graphql(complex)]
struct Post {
    #[serde(rename = "_id")]
    pub id: ObjectId,
    pub title: String,
    // I could do something like
    // #[serde(default)]
    pub body: String,
}

#[ComplexObject]
impl Post {
    async fn text_snippet(amp;self) -> amp;str {
        let length = self.body.len();
        let end = min(length, 5);
        amp;self.body[0..end]
    }
}

struct Query;
#[Object]
impl Query {
    // fetching posts
    async fn posts<'ctx>(amp;self, ctx: amp;Context<'ctx>) -> Vec<Post> {
        let posts = ctx.data_unchecked::<Collection<Post>>();
        let projection = // getting the projection doc here based on graphql fields, lets say doc! {"title": 1}

        let options = FindOptions::builder().limit(10).projection(projection).build();
        let cursor = posts.find(None, options).await.unwrap();

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

Но когда я выполняю запрос

 {
    posts {
        id
        title
        textSnippet
    }
}
 

я получаю

 thread 'actix-rt:worker:0' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: BsonDecode(DeserializationError { message: "missing field `body`" }), labels: [] }', server/src/schema/post.rs:20:46
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 

и когда я делаю #[serde(default)] что-то с телом, а затем запрашиваю textSnippet, а не тело, textSnippet-это пустая строка.

Как мне это исправить?

Ответ №1:

Не могли бы вы завернуть каждое поле в Post Option и позволить try_collect заполнить возвращенные поля за вас?

Ответ №2:

Вы можете создать структуру с теми файлами, которые вам нужны, и использовать коллекцию новой структуры.

 use async_graphql::*;
use serde::{Deserialize, Serialize};
use mongodb::{bson::doc, bson::oid::ObjectId, options::FindOptions, Collection};

#[derive(SimpleObject, Serialize, Deserialize, Debug)]
#[graphql(complex)]
struct Post {
    #[serde(rename = "_id")]
    pub id: ObjectId,
    pub title: String,
    // I could do something like
    // #[serde(default)]
    pub body: String,
}

#[derive(SimpleObject, Serialize, Deserialize, Debug)]
#[graphql(complex)]
struct PostTitle {
    #[serde(rename = "_id")]
    pub id: ObjectId,
    pub title: String,
}

struct Query;
#[Object]
impl Query {
    // fetching posts
    async fn posts<'ctx>(amp;self, ctx: amp;Context<'ctx>) -> Vec<PostTitle> {
        let posts = ctx.data_unchecked::<Collection<PostTitle>>();
        let projection = doc! {"title": 1}

        let options = FindOptions::builder().limit(10).projection(projection).build();
        let cursor = posts.find(None, options).await.unwrap();

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

Комментарии:

1. Да, поставьте, тогда вам нужно было бы заранее знать, какие запросы вы бы выполнили. Мне нужно, чтобы он был более гибким.