简体   繁体   中英

merge two JSON arrays with a common key golang

it's days I try to merge two jons based on a common key. I have in input two different JSONs with a common field, I would like to merge the data of the two json based on the common key. A sort of sql join between the two JSON.

JSON derives from this code

func Dati_plus(c *gin.Context) {

oracle, err := http.Get("http://XXXX/XXX")
    if err != nil {
            panic(err)
    }
defer oracle.Body.Close()

mysql, err := http.Get("http://XXXX/XXX")
if err != nil {
        panic(err)
}
defer mysql.Body.Close()

oracleJSON, err := ioutil.ReadAll(oracle.Body)
if err != nil {
        panic(err)
}
mysqlJSON, err := ioutil.ReadAll(mysql.Body)
if err != nil {
        panic(err)
}

var oracleOUT map[string]interface{}
var mysqlOUT map[string]interface{}

json.Unmarshal([]byte(oracleJSON), &oracleOUT)
json.Unmarshal([]byte(mysqlJSON), &mysqlOUT)

a := map[string]interface{}{"result":mysqlOUT["result"]}
b := map[string]interface{}{"result":oracleOUT["result"]}

the JSONs in input have this form

{"count":2,"result":[{"DESC":"2","NOMEmy":"PIPPO","COGNOMEmy":"PIPPO"},{"DESC":"7","NOMEmy":"PIPPO","COGNOMEmy":"PIPPO"}]

{"count":2,"result":[{"DESC":"2","COS":"PIPPO","ROS":"PIPPO"},{"DESC":"7","COS":"PIPPO","ROS":"PIPPO"},{"DESC":"60","COS":"PIPPO","ROS":"PIPPO"}]

If i have two json like this the result of the function it should be

{"count":2,"result":[{"DESC":"2","COS":"PIPPO","ROS":"PIPPO","NOMEmy":"PIPPO","COGNOMEmy":"PIPPO"},{"DESC":"7","COS":"PIPPO","ROS":"PIPPO","NOMEmy":"PIPPO","COGNOMEmy":"PIPPO"},{"DESC":"60","COS":"PIPPO","ROS":"PIPPO"}]

if it can help, this is a function I use for merge between two single-value JSONs, but I could not modify it in the right way

    func merge(dst, src map[string]interface{}, depth int) map[string]interface{} {
    if depth > MaxDepth {
        panic("Troppo Lungo")
    }
    for key, srcVal := range src {
        if dstVal, ok := dst[key]; ok {
            srcMap, srcMapOk := mapify(srcVal)
            dstMap, dstMapOk := mapify(dstVal)
            if srcMapOk && dstMapOk {
                srcVal = merge(dstMap, srcMap, depth+1)
            }
        }
        dst[key] = srcVal
    }
    return dst
}

    func mapify(i interface{}) (map[string]interface{}, bool) {
        value := reflect.ValueOf(i)
        if value.Kind() == reflect.Map {
            m := map[string]interface{}{}
            for _, k := range value.MapKeys() {
                m[k.String()] = value.MapIndex(k).Interface()
            }
            return m, true
        }
        return map[string]interface{}{}, false
    }

Please, Help Me. THX

One observation here is that you can define a simple type that will model both of your data sets and use the golang type system to your advantage (instead of working against it by using so much reflection), for example:

type Data struct {
  Count   int                 `json:"count"`
  Results []map[string]string `json:"result"`
}

// ...
oracleData, mysqlData := Data{}, Data{}
err := json.Unmarshal([]byte(oracleJson), &oracleData)
check(err)
err := json.Unmarshal([]byte(mysqlJson), &mysqlData)
check(err)

Now your "merge" function can simply return a new "Data" struct with values populated from the two inputs without having to worry about type assertions or casting. One key feature of this implementation is that it creates a lookup table of data result objects by their "DESC" key, which is later used for correlation:

func merge(d1, d2 Data) Data {
  // Create the lookup table by each result object "DESC".
  d1ResultsByDesc := map[string]map[string]string{}
  for _, obj1 := range d1.Results {
    d1ResultsByDesc[obj1["DESC"]] = obj1
  }

  newData := Data{}
  for _, obj2 := range d2.Results {
    newObj := map[string]string{}
    // Include all result data objects from d2
    for k2, v2 := range obj2 {
      newObj[k2] = v2
    }
    // Also include the matching result data from d1
    obj1 := d1ResultsByDesc[obj2["DESC"]]
    for k1, v1 := range obj1 {
      newObj[k1] = v1
    }
    newData.Results = append(newData.Results, newObj)
  }

  return newData
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM