-2

How to parse this json using Go?

 timelinedata := '{
   "2016-08-17T00:00:00.000Z": 4,
   "2016-11-02T00:00:00.000Z": 1,
   "2017-08-30T00:00:00.000Z": 1
   } '

I want the dates and the values in separate variables by looping over the json. Currently I am doing it in this way

var timeline map[string]int

json.Unmarshal([]byte(timelinedata),

for k, v := range timeline {
            new_key := k
            new_val := v
            println("val--->>", new_key, new_val)
        }

The problem is that the output is not in proper order as like the json input is. Every time I run the loop the output order varies. I want to map the json in exact order as like the input. I think I am not maping it in a proper way---

veerg404
  • 111
  • 1
  • 7
  • 1
    Maps are unordered in go, that's why. – Ullaakut Nov 07 '18 at 06:29
  • 3
    Well, you cannot do this (at least not in a simple way): Your JSON is an object and its fields are _unordered_. So are maps in Go. What you can do (See linked answer) is sort the timestamps. This will give you the time in sorted order which may differ from your input order (which is _unordered_). If your input really would have an order it would be ab JSON _array_ and not an object. – Volker Nov 07 '18 at 06:50
  • @Volker That actually qualifies to be the answer. – icza Nov 07 '18 at 07:32

1 Answers1

3

You should not assume that the key order in a JSON object means anything:

From the introduction of RFC 7159 (emphasis mine):

An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.

An array is an ordered sequence of zero or more values.

In addition to that, you shouldn't assume that the producer of the JSON document has been in control of the key/value order; maps are unordered in most languages, so it mostly comes down to the used encoding library. If the producer did care about the order, they would use an array.

That being said, if you really are interested in the order of the JSON keys, you have to decode the object piece by piece, using json.Decoder.Token:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

func main() {
    j := `{
        "2016-08-17T00:00:00.000Z": 4,
        "2016-11-02T00:00:00.000Z": 1,
        "2017-08-30T00:00:00.000Z": 1
    }`

    dec := json.NewDecoder(strings.NewReader(j))
    for dec.More() {
        t, err := dec.Token()
        if err != nil {
            log.Fatal(err)
        }

        switch t := t.(type) {
        case json.Delim:
            // no-op
        case string:
            fmt.Printf("%s => ", t)
        case float64:
            fmt.Printf("%.0f\n", t)
        case json.Number:
            fmt.Printf(" %s\n", t)
        default:
            log.Fatalf("Unexpected type: %T", t)
        }
    }
}

Try it on the Playground: https://play.golang.org/p/qfXcOfOvKws

Community
  • 1
  • 1
Peter
  • 29,454
  • 5
  • 48
  • 60