I know the title seems generic and a duplicate, but i've tried many of the options from previous questions, and I can't use a struct here
My system is using the messaging service NATS to sends maps between a subscriber and a publisher. The subscriber takes the received map, and inserts it as a document in a MongoDB collection
The problem I have is that floats and ints are inserted as strings!
In my code, the recipe is a configuration file that sets the datatypes of the columns received in the map. Think of it as a series of keys like this:
Here's the code that creates the map with the right datatypes
mapWithCorrectDataTypes := make(map[string]interface{})
for columnNameFromDataTypesInRecipe, datatypeForColumnInRecipe := range dataTypesFromRecipeForColumns {
for natsMessageColumn, natsMessageColumnValue := range mapFromNATSMessage {
//If the column in the NATS message is found in the recipe, format the data as dictated in the recipe
if natsMessageColumn == columnNameFromDataTypesInRecipe {
if datatypeForColumnInRecipe.(string) == "string" {
natsMessageColumnValue = natsMessageColumnValue.(string)
mapWithCorrectDataTypes[columnNameFromDataTypesInRecipe] = natsMessageColumnValue
}
if datatypeForColumnInRecipe.(string) == "int" {
convertedInt, err := strconv.Atoi(mapFromNATSMessage[columnNameFromDataTypesInRecipe].(string))
if err != nil {
fmt.Println("ERROR -->", err)
}
mapWithCorrectDataTypes[columnNameFromDataTypesInRecipe] = convertedInt
}
if datatypeForColumnInRecipe.(string) == "float64" {
convertedFloat, err := strconv.ParseFloat(mapFromNATSMessage[columnNameFromDataTypesInRecipe].(string), 64)
if err != nil {
fmt.Println("ERROR -->", err)
}
mapWithCorrectDataTypes[columnNameFromDataTypesInRecipe] = convertedFloat
fmt.Println("TYPE -->", reflect.TypeOf(mapWithCorrectDataTypes[columnNameFromDataTypesInRecipe]))
}
} else {
//If column not found in the recipe, format as a string
mapWithCorrectDataTypes[natsMessageColumn] = natsMessageColumnValue.(string)
}
}
}
From the last line I put in a print statement for float64s to check that the datatype for this key in the map is correct, and it passes this test!
My question is this: If the data types are correctly being set in the map, why when the map is inserted as a document in MongoDB are the floats and ints set as strings?!
What I have tried so far:
Marshalling and unmarshalling the map as an interface, then inserting the record:
jsonVersionOfMap, err := json.Marshal(mapWithCorrectDataTypes)
if err != nil {
fmt.Println("ERROR -->", err)
}
var interfaceForJSON interface{}
json.Unmarshal(jsonVersionOfMap, &interfaceForJSON)
fmt.Println("JSON -->", interfaceForJSON)
err = mongoConnection.Insert(interfaceForJSON)
if err != nil {
fmt.Println("Error inserting MongoDB documents", err)
}
What am I missing here?
See the result with the incorrectly formatted data:
this may not be a fix. But i've resolved the issue i've been having. I'm using a publisher and a subscriber via NATS. Previously I was creating a map with all the data, then sending that out as a message, then the subscriber takes the map from the message, and processing the datatypes (on the subscriber side)
To fix the problem that I was experiencing, I instead formatted the maps' values on the publisher side. So I instead moved my code that checks for the datatype over to the NATS publisher, and not the code that processes the incoming message
I understand this isn't an ideal solution, but if you're using NATS and find you're having the same issue. Try this