darccio / mergo

Mergo: merging Go structs and maps since 2013

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mergo not overriding destination with source

RomilShah opened this issue · comments

I am trying to merge values of 2 JSON into 1, where value of source should override value of destination. It is working fine for most the cases except for the case where value of 1 hashmap is string and other value is another hashmap. Below is the code snipped

package main

import (
	"encoding/json"
	"fmt"

	"github.com/imdario/mergo"
)

var (
	a = "{\"a\": \"60\"}"
	b = "{\"a\": { \"name\":\"asprin\", \"dose\":0.12,\"stt\":true} }"
)

func main() {
	var source, destination map[string]interface{}

	err := json.Unmarshal([]byte(a), &destination)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal([]byte(b), &source)
	if err != nil {
		panic(err)
	}

	fmt.Println(destination, source)
	err = mergo.MergeWithOverwrite(&destination, &source, mergo.WithOverride, mergo.WithTypeCheck)
	if err != nil {
		panic(err)
	}
	fmt.Println(&destination, "  <-- result")

}

playground: https://go.dev/play/p/BTmRc7wf6Js

Current output is

&map[a:60] <-- result which is value of destination. Mergo is not changing anything

Excepted output is

map[a:map[dose:0.12 name:asprin stt:true]] <--result

or at-least give error that it is not possible to merge hashmap to string`

It looks like you're looking for something like github.com/mitchellh/mapstructure instead which is exactly tailored for use cases “where you don't quite know the structure of the underlying data until you read a part of it“. In your case a is a number in the first map, bur changes to a object in the second which is a different type. mergo is strong when it comes to merging structs o the same type.
mergo provides a Map function, but mapstructure fits better because it is the main goal of the project to handle maps.

@RomilShah This code works as you expected:

package main

import (
	"encoding/json"
	"fmt"

	"dario.cat/mergo"
)

var (
	a = "{\"a\": \"60\"}"
	b = "{\"a\": { \"name\":\"asprin\", \"dose\":0.12,\"stt\":true} }"
)

func main() {
	var source, destination map[string]interface{}

	err := json.Unmarshal([]byte(a), &destination)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal([]byte(b), &source)
	if err != nil {
		panic(err)
	}

	err = mergo.Map(&destination, source, mergo.WithOverride)
	if err != nil {
		panic(err)
	}
	fmt.Println(destination, "  <-- result")

}

It even works if you use Merge instead of Map, making mergo equivalent to mapstructure. Merging structs or maps is the same logic, although in Mergo Map is a specialized case of Merge.