I am facing a issue with update document using golang mongo driver.
Scenario: I want to update a field that is nested in a struct. For ex: StructOuter -> structInner -> field1, field2, field3. Now if I want to update the field3 and I have the corresponding value as another struct, how can i go ahead by just updating this field alone. I tried with code below but it updates the whole structInner leaving only field3:
I think the issue is that doing a $set will overwrite the entire subdocument, so if you only specify the value for z, the document will become
{x: {y: {z: <newValue>}}}
I think you can instead do
{$set: {x.y.z: 2}}
which will only set the z field and leave the other value unchanged.
Also, note that this question is not specific to the Go driver, as the driver just forwards your update document to the server. It may be helpful to instead provide an example of the existing document and an example of the updated document you want, and then others outside the driver team can help write the update syntax for your use case.
I am facing a issue with update document using golang mongo driver.
Scenario: I want to update a field that is nested in a struct. For ex: StructOuter -> structInner -> field1, field2, field3. Now if I want to update the field3 and I have the corresponding value as another struct, how can i go ahead by just updating this field alone. I tried with code below but it updates the whole structInner leaving only field3:
Field changed is data.field_three. The update request has been populated in struct. but when the bson masrshall and unmarshall is used to form bson.M from it, the map created is multiple nested.
Just want to know if this is supported, if yes can you help me with it and also point to some deep dive links on this.
Thanks for the description and example. But I was looking at some prewritten script as a part of mongo package.
After your reply, I wrote the below script (a bit specific to my use case) to generate keys(ex:- dat.field_three) for all the fields in n-level nested struct. Pasting it below:
func main() {
// prod is a large struct
var updateFields bson.M
conv, _ := bson.Marshal(prod)
bson.Unmarshal(conv, &updateFields)
updateFields = ParseBsonMap(updateFields)
}
func ParseBsonMap(aMap map[string]interface{}) bson.M {
finalMap := make(map[string]interface{})
parseMap("", aMap, &finalMap)
return finalMap
}
func parseMap(k string, aMap map[string]interface{}, finalMap *map[string]interface{}) {
if len(aMap) == 0 {
(*finalMap)[k] = nil
return
}
for key, val := range aMap {
if val != nil {
switch concreteVal := val.(type) {
case map[string]interface{}:
parseMap(getKey(k, key), val.(map[string]interface{}), finalMap)
case []interface{}:
(*finalMap)[getKey(k, key)] = val.([]interface{})
default:
concreteValType := reflect.TypeOf(concreteVal)
if concreteValType.Kind() == reflect.Map {
parseMap(getKey(k, key), concreteVal.(primitive.M), finalMap)
} else {
(*finalMap)[getKey(k, key)] = concreteVal
}
}
} else {
(*finalMap)[getKey(k, key)] = nil
}
}
}
func getKey(k string, key string) string {
if k == "" {
return key
}
return k + "." + key
}