1

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}
Zeke Lu
  • 6,349
  • 1
  • 17
  • 23
echo
  • 767
  • 2
  • 9
  • 24

2 Answers2

2

I suggest creating a type and removing the field you don't need.

package main

import (
    "encoding/json"
    "log"
)

type A struct {
    Timestamp int64 `json:"timestamp"`
}

func main() {
    jsonBatch := `{"timestamp":1684366653200744506, "todelete":"string value or boolean value"}`
    i := A{}
    if err := json.Unmarshal([]byte(jsonBatch), &i); err != nil {
        log.Println("json UnMarshal from batch json failed")
        log.Println(err)
    }
    dbJsonBatch, err := json.Marshal(i)
    if err != nil {
        log.Println("json Marshal from batch json failed")
        log.Println(err)
    }
    log.Println("json Marshal from maps of key string and value interface to batch json for insert to DB")
    log.Println(string(dbJsonBatch))
}

This prints

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":1684366653200744506}
Computer's Guy
  • 5,122
  • 8
  • 54
  • 74
  • yeah, I actually get the json from Marshaling a existing struct but needs to remove a few fields conditionally, so I converted it to a map and then delete few keys to avoid recreating a similar struct just without the fields I don't need. I am trying to delete fields within different if conditions, it seems like I need a different struct within each if statement to unmarshal the json to? – echo May 18 '23 at 00:31
2

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.

Zeke Lu
  • 6,349
  • 1
  • 17
  • 23