Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUST-677 Serialization formatting options #230

Open
AlexKovalevych opened this issue Feb 9, 2021 · 2 comments
Open

RUST-677 Serialization formatting options #230

AlexKovalevych opened this issue Feb 9, 2021 · 2 comments
Labels
tracked-in-jira Ticket filed in Mongo's Jira system

Comments

@AlexKovalevych
Copy link

After retrieving data from database like:

use mongodb::bson::from_document;

let data = from_document::<Value>(bson_document)?;

I'm not able to serialize data to json with custom datetime format getting datetime fields like:

...
        "updated_at": {
          "$date": "2021-02-01T14:50:01.504Z"
        },
...

I can't use serde helpers, since i don't know the data schema. The only solution i see right now is to manually iterate all fields in bson_document recursively and in case of Bson::DateTime type convert it to Bson::String type with desired datetime format. Is there a better solution?

@patrickfreed
Copy link
Contributor

Hi @AlexKovalevych!

So right now, the only format we support for deserializing arbitrary BSON to an arbitrary serialization format is Extended JSON, which is what you're seeing there with the $date. We think allowing configuration in this area would be a nice addition to our API, so I've filed RUST-677 to track the work for that.

In the meantime, you could define a wrapper struct and implement a custom Serialize implementation on it, which could possibly make this a little more straightforward.

Here's a pretty inefficient example using a lot of clones:

struct MyWrapper {                                                                                         
    wrapped: Bson                                                                                          
}                                                                                                          
                                                                                                           
impl Serialize for MyWrapper {                                                                             
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>                                       
    where                                                                                                  
        S: serde::Serializer                                                                               
    {                                                                                                      
        match self.wrapped {                                                                               
            Bson::DateTime(ref d) => {                                                                     
                d.serialize(serializer)                                                                    
            }                                                                                              
            Bson::Document(ref d) => {                                                                     
                let map: HashMap<String, MyWrapper> = d.iter().map(|(k, v)| {                              
                    (k.clone(), MyWrapper { wrapped: v.clone() })                                          
                }).collect();                                                                              
                map.serialize(serializer)                                                                  
            },                                                                                             
            Bson::Array(ref a) => {                                                                        
                let vec: Vec<MyWrapper> = a.iter().map(|b| { MyWrapper { wrapped: b.clone() } }).collect();
                vec.serialize(serializer)                                                                  
            }                                                                                              
            ref a @ _ => a.serialize(serializer)                                                           
        }                                                                                                  
    }                                                                                                      
}                                                                                                          

And then you'd use serde_json's serialization functionality:

let doc = doc! { "date": Bson::DateTime(Utc::now()) };                               
let json = serde_json::to_value(MyWrapper { wrapped: Bson::Document(doc) }).unwrap();
println!("{}", json);  // {"date":"2021-02-20T00:36:46.597117805Z"}                                                              

This could be optimized to get rid of the clones, but this was just the simplest way I could think of implementing it for demonstration purposes.

@patrickfreed patrickfreed added the tracked-in-jira Ticket filed in Mongo's Jira system label Feb 20, 2021
@AlexKovalevych
Copy link
Author

Got it, thank you for detailed response

@patrickfreed patrickfreed changed the title Any way to set default datetime format? RUST-677 Serialization formatting options Feb 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tracked-in-jira Ticket filed in Mongo's Jira system
Projects
None yet
Development

No branches or pull requests

2 participants