Home > Software engineering >  How to upsert into concurrent map while iterating over regular map?
How to upsert into concurrent map while iterating over regular map?

Time:03-07

I need to have a map of string as key and unique (no dupes) int64 array as value so I decided to use something like below so that value can act as a set.

var customerCatalog = make(map[string]map[int64]bool)

Above map is populated with some data in it. Now I am trying to populate my concurrent map in golang by reading above regular customerCatalog map but I am getting error:

for k, v := range customerCatalog {
  r.customerCatalog.Upsert(k, v, func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
    typedNewValue := newValue.([]int64)
    if !exists {
      return typedNewValue
    }
    typedValueInMap := valueInMap.([]int64)
    return append(typedValueInMap, typedNewValue...)
  })
}

This is the error I am getting. I am using upsert method as shown here

panic: interface conversion: interface {} is map[int64]bool, not []int64

What is wrong I am doing?

CodePudding user response:

I believe a minimal, reproducible, example of your issue would be as follows (playground):

conMap := cmap.New()

v := map[int64]bool{}
updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
    _ = newValue.([]int64)
    return nil
}

conMap.Upsert("foo", v, updateItemFn)

Note: I have stripped out the loop etc because that is irrelevant to the panic. However you should note that because the loop iterates over a map[string]map[int64]boolthe type of v will be map[int64]bool.

The Upsert function looks up the key in the map and then passes it and the value you passed in to the function.

So your function is receiving a map[int64]bool and the first thing it does is to assert that this is a []int64 (which will fail because it's not). To fix this you need to convert the map[int64]bool into a []int64. This could be done before calling the Upsert or within your implementation of UpsertCb as shown here (playground):

conMap := cmap.New()
conMap.Set("foo", []int64{5, 6})

v := map[int64]bool{
    1: true,
}

updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
    m := newValue.(map[int64]bool)
    a := make([]int64, 0, len(m))
    for k := range m {
        a = append(a, k)
    }
    if valueInMap == nil { // New value!
        return a
    } else {
        typedValueInMap := valueInMap.([]int64)
        return append(typedValueInMap, a...)
    }
    return a
}

conMap.Upsert("foo", v, updateItemFn)

fmt.Println(conMap.Get("foo"))

The above has been kept simple to demonstrate the point; in reality you may want to add all of the values into a map so as to avoid duplicates.

  • Related