2

I have a sample JSON body that contains some strings. I want some of the strings to be converted into Mongo Extended JSON. For example, the JSON body passed in is the following:

{
    "GuidBinary": "734cba69-4851-4869-8d0e-e870d6fb3065",
    "DateTime": "12/12/2012",
    "RegularString": "abcd"
}

And I want to convert this into

{
    "GuidBinary": {
        "$binary": {
            "base64": "<payload>",
            "subType": 0x03
        }
    },
    "DateTime": {"$date": "<ISO-8601 Date/Time Format>"},
    "RegularString": "abcd"
}

Is there a way to do this in Go, either through a package like mongo-go-driver or another method?

icza
  • 389,944
  • 63
  • 907
  • 827
Riaru Neimu
  • 43
  • 1
  • 9

1 Answers1

1

Yes, it's possible. It's part of the official mongo-go driver. Generating this extended JSON is published as the bson.MarshalExtJSON() function.

Example using it:

m := map[string]interface{}{
    "GuidBinary":    []byte{1, 2, 3, 4, 5},
    "DateTime":      time.Now(),
    "RegularString": "abcd",
}

out, err := bson.MarshalExtJSON(m, false, false)
fmt.Println(string(out), err)

This will output (try it on the Go Playground):

{"DateTime":{"$date":"2009-11-10T23:00:00Z"},"RegularString":"abcd",
    "GuidBinary":{"$binary":{"base64":"AQIDBAU=","subType":"00"}}} <nil>

So what you need to do is unmarshal your original JSON (using the encoding/json package), and you need to do some post processing on it: GuidBinary is a regular string in the input JSON, but it represents a UUID. You need to parse it into a UUID value (there are probably lots of libraries for this).

You also need to convert (parse) the DateTime which is also given as a JSON text in the input, but it represents a date. Use time.Parse() for this. And now you can call bson.MarshalExtJSON() to generate the extended JSON.

icza
  • 389,944
  • 63
  • 907
  • 827
  • 1
    Suppose I want to do the post-processing as part of the step of unmarshalling the original JSON. Do you have a recommendation on how to do this? I was thinking of creating string types for the binary data and the dates, then setting up a custom unmarshaller on those string types, but I'm not too certain how that works. – Riaru Neimu Jan 17 '20 at 22:07
  • @RiaruNeimu It would be enough to unmarshal into a simple map or struct, and do the post processing part manually, to create the UUID and `time.Time` values, and pass the new struct or map to `MarshalExtJSON()`. – icza Jan 17 '20 at 22:16