[英]Update Nested fields using Golang struct
我面临使用 golang 更新结构字段的问题
正如 var 名称所暗示的那样,一些当前的配置字段应该使用请求的配置进行更新
currentConfig:=`
{
"field_one": "value",
"data": {
"field_two": [
"data1",
"data2"
],
"field_three": "check",
"field_four": 12
},
"field_five": [
"data1",
"data2"
],
"data2": {
"field_six":{
"field_seven": 100
}
}
}`
updateRequest:=`
{
"data": {
"field_three": "updated check" //ignore if same value exist (field_three exists in current config)
},
"field_five": ["data3"], // append to current config
"data2": {
"field_six":{
"field_eight": 300 // add value if doesnt exist to current
}
}
}`
func main() {
config := make(map[string]interface{})
err := json.Unmarshal([]byte(currentConfig), &config)
if err != nil {
panic(err)
}
updateFields := make(map[string]interface{})
err1 := json.Unmarshal([]byte(updateRequest), &updateFields)
if err1 != nil {
panic(err1)
}
fmt.Println(config)
updateFields = ParseJsonMap(updateFields, config)
fmt.Println(updateFields)
}
func ParseJsonMap(aMap map[string]interface{}, finalMap map[string]interface{}) 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{}:
if _, ok := (*finalMap)[getKey(k, key)]; ok {
parseMap(getKey(k, key), val.(map[string]interface{}), finalMap)
} else {
(*finalMap)[getKey(k, key)] = val
}
case []interface{}:
res := val.([]interface{})
if arr, ok := (*finalMap)[getKey(k, key)]; ok {
for _, valueIn := range res {
arr = append(arr.([]interface{}), valueIn)
}
(*finalMap)[getKey(k, key)] = arr
} else {
(*finalMap)[getKey(k, key)] = res
}
default:
concreteValType := reflect.TypeOf(concreteVal)
if concreteValType.Kind() == reflect.Map {
parseMap(getKey(k, key), concreteVal.(map[string]interface{}), finalMap)
} else {
if _, ok := (*finalMap)[getKey(k, key)]; !ok {
(*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
}
预期结果
map[data:map[field_four:12 field_three:check field_two:[data1 data2]] data2:map[field_six:map[field_eight:300 field_seven:100]] field_five:[data1 data2 data3] field_one:value]
{
"field_one": "value",
"data": {
"field_two": [
"data1",
"data2"
],
"field_three": "check", //since key exist with data not updated
"field_four": 12
},
"field_five": [
"data1",
"data2",
"data3" //data 3 appended
],
"data2": {
"field_six":{
"field_seven": 100,
"field_eight": 300 //field is added
}
}
}
结果得到 - 在顶层创建密钥
map[data:map[field_four:12 field_three:check field_two:[data1 data2]] data.field_three:check changed data2:map[field_six:map[field_seven:100]] data2.field_six:map[field_eight:300] field_five:[data1 data2 data3] field_one:value]
只是想知道这是否受支持,如果是,你能帮我吗,如果有更好的方法存在
看来您正在尝试将一个 map 叠加到另一个 map 上。如果您不想在不更改现有 map 的情况下应用此类更新,这会变得很复杂。因此,将这两个步骤分开可能更容易:
map[string]interface{}
map[string]interface{}
叠加在另一个之上func CopyMap(m map[string]interface{}) map[string]interface{} {
cp := make(map[string]interface{})
for k, v := range m {
vm, ok := v.(map[string]interface{})
if ok {
cp[k] = CopyMap(vm)
} else {
cp[k] = v
}
}
return cp
}
func overlay(dst, src map[string]interface{}) error {
for k, v := range src {
if _, ok := dst[k]; !ok {
dst[k] = v // easy case - dst key does not exist
continue
}
d, ok1 := dst[k].(map[string]interface{})
s, ok2 := src[k].(map[string]interface{})
if ok1 && ok2 {
overlay(d, s) // merge case
} else if !ok1 && !ok2 {
dst[k] = v // non-map - so simple assignment/reassignment
} else {
return fmt.Errorf("incompatible update types") // map to non-map or vice-versa
}
}
return nil
}
使用:
err := json.Unmarshal([]byte(currentConfig), &config) // check err
err = json.Unmarshal([]byte(updateRequest), &updateFields) // check err
newconfig = CopyMap(config)
err = overlay(newconfig, updateFields) // check err
https://play.golang.org/p/RZPbkv19ChL
Output:
config : map[data:map[field_four:12 field_three:check field_two:[data1 data2]] data2:map[field_six:map[field_eight:200 field_seven:100]] field_five:[data1 data2] field_one:value]
update : map[data:map[field_three:check changed] data2:map[field_six:map[field_eight:300]] field_five:[data1]]
newconfig : map[data:map[field_four:12 field_three:check changed field_two:[data1 data2]] data2:map[field_six:map[field_eight:300 field_seven:100]] field_five:[data1] field_one:value]
更新:处理 JSON arrays 的追加而不是替换:
func overlay2(dst, src map[string]interface{}) error {
for k, v := range src {
if _, ok := dst[k]; !ok {
dst[k] = v // easy case - dst key does not exist
continue
}
dm, ok1 := dst[k].(map[string]interface{})
sm, ok2 := src[k].(map[string]interface{})
if ok1 && ok2 {
overlay2(dm, sm) // merge case
continue
}
ds, ok1 := dst[k].([]interface{})
ss, ok2 := src[k].([]interface{})
if ok1 && ok2 {
dst[k] = append(ds, ss...) // JSON array case
continue
}
return fmt.Errorf("unhandled type/update")
}
return nil
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.