Search code examples
jsongoprecision

JSON number gets cut off after unmarshaling to interface


So I have a JSON with many fields and I am looping through it as suggested by How effectively to change JSON keys to delete some of the keys I don't need. But after deletion, the original values of the existing JSON was changed, some of them are float numbers it seems and I made a demo to show it.

How can I change this behavior? Is the interface{} causing the issue? Why is 1684366653200744506 cut off to 1684366653200744400?

Thanks!

https://go.dev/play/p/X2auWqWB2fL

For reference, the output JSON is changed to 1684366653200744400

2009/11/10 23:00:00 1684366653200744448.000000
2009/11/10 23:00:00 map[timestamp:1.6843666532007444e+18]
2009/11/10 23:00:00 json Marshal from maps of key string and value interface to batch json for insert to DB
2009/11/10 23:00:00 {"timestamp":1684366653200744400}

Solution

  • It's because by default, the encoding/json package stores float64 in the interface value for JSON numbers. See json.Unmarshal:

    To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:

    • bool, for JSON booleans
    • float64, for JSON numbers
    • ...

    You can create a decoder and call (*Decoder).UseNumber to change the behavior:

    jsonBatch := `{"timestamp":1684366653200744506, "todelete":"string value or boolean value"}`
    dec := json.NewDecoder(strings.NewReader(jsonBatch))
    dec.UseNumber()
    var i interface{}
    if err := dec.Decode(&i); err != nil {
    

    See https://go.dev/play/p/ZjWB-NfiEQL.