Search code examples
mongodbruststructoption-type

What is the best way to access data within nested structs, all of which are Optional using MongoDB's Rust driver?


I have a set of structs that are nested, and all the data is optional. Structs are similar to the following (for simplicity I've removed some of the Optionals):

#[derive(Debug, Serialize, Deserialize)]
pub struct Device {
    #[serde(rename = "_id")]
    pub id: Option<bson::oid::ObjectId>,
    pub system: Option<System>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct System {
    pub id: Option<u32>,
    pub mac: Option<String>,
}

When I query the db, I get the data:

Ok(Some(Device { id: Some(ObjectId("...")),  system: Some(System { id: Some(123), mac: Some("1234") })}))

I am trying to access the id value within the System struct. I can access it easily with a few nested match statements, but I was wondering if there is an easier solution. I've been looking at unwrap_or, unwrap_or_else, but I haven't been able to get the syntax correct. Ideally returning a 0 will suffice, as that value is used to denote an error within the application structure. The nested match statements work fine - it is just a bit verbose.

Alternatively I could also just use the aggregation pipeline to get the value. I'm just curious about alternatives.

Thanks.


Solution

  • You can use and_then to apply a function to the contained Ok value, and leave Nones unchanged. For example, imagine the following structure:

    struct Foo {
        bar: Option<Bar>
    }
    
    struct Bar {
        baz: Option<Baz>
    }
    
    struct Baz {
        value: Option<i32>
    }
    

    You can then query the nested data like:

    fn read_value(foo: Foo) -> Option<i32> {
        foo.bar
            .and_then(|bar| bar.baz) 
            .and_then(|baz| baz.value)
    }
    

    If any of the Option's are None, the whole expression will be None, otherwise it will be the contained Some(value)