Search code examples
rustserde

How to mutate serde_json value by adding additional fields?


So I have a serde Value from somewhere and I would like to add additional "fields" to the Value before deserializing it afterwards. I'm looking through the docs but I don't see how to do it.

More specifically, let's say I have a HashMap whose values I want to merge into the Value.

pub fn merge(v: &Value, fields: &HashMap<String, String>) -> Value

Solution

  • You need to extract the Map (in the Value::Object case), copy it (as you're only taking an &Value input), update it, and re-wrap it in a Value::Object e.g.

    pub fn merge(v: &Value, fields: &HashMap<String, String>) -> Value {
        match v {
            Value::Object(m) => {
                let mut m = m.clone();
                for (k, v) in fields {
                    m.insert(k.clone(), Value::String(v.clone()));
                }
                Value::Object(m)
            }
            v => v.clone(),
        }
    }
    

    (on conflict this will override v's entries with fields's).

    Note that merge could be a lot more efficient if it took the arguments by value as it would not have to copy them.

    Instead, it could then update the Object's map in-place (then return the updated value), and return the rest as-is. It could also take v by mutable reference and update the map in-place (and ignore any non-Object Value) in which case it would not need to return anything.