簡體   English   中英

使用 Golang 結構更新嵌套字段

[英]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
}

https://play.golang.org/p/i-0yXMcqU7Z

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM