Skip to content

Commit 8b35c0b

Browse files
authored
DOCSP-47011: Extended JSON (#528)
* DOCSP-47011: Extended JSON * wip * LM PR fixes 1 * QH tech review comment 1
1 parent 8cac163 commit 8b35c0b

File tree

3 files changed

+348
-3
lines changed

3 files changed

+348
-3
lines changed

source/data-formats.txt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
.. This page is hidden from the TOC and search indexing.
2+
3+
.. meta::
4+
:robots: noindex, nosnippet
5+
16
.. _golang-data-formats:
27

38
========================
@@ -15,12 +20,22 @@ Specialized Data Formats
1520
:values: reference
1621

1722
.. meta::
18-
:keywords: bson, uuid, date, time
19-
20-
.. TODO Landing page
23+
:keywords: bson, JSON, date, time, marshal, unmarshal, serialization
2124

2225
.. toctree::
2326
:titlesonly:
2427
:maxdepth: 1
2528

2629
BSON </data-formats/bson>
30+
Extended JSON </data-formats/extended-json>
31+
32+
Overview
33+
--------
34+
35+
You can use several types of specialized data formats in the
36+
{+driver-short+}. To learn how to work with these data formats, see the
37+
following guides:
38+
39+
- Learn how to work with BSON documents in the :ref:`golang-bson` guide.
40+
- Learn how to convert between {+language+} types and Extended JSON in the
41+
:ref:`golang-extended-json` guide.

source/data-formats/extended-json.txt

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
.. _golang-extended-json:
2+
3+
===================================
4+
Document Data Format: Extended JSON
5+
===================================
6+
7+
.. contents:: On this page
8+
:local:
9+
:backlinks: none
10+
:depth: 2
11+
:class: singlecol
12+
13+
.. facet::
14+
:name: genre
15+
:values: reference
16+
17+
.. meta::
18+
:keywords: code example, bson, relaxed, canonical, legacy
19+
20+
Overview
21+
--------
22+
23+
JSON is a data format that represents the values of objects, arrays, numbers,
24+
strings, booleans, and nulls. The **Extended JSON** format defines a reserved
25+
set of keys prefixed with the ``$`` character to represent field type
26+
information that directly corresponds to each type in BSON, the format
27+
that MongoDB uses to store data.
28+
29+
Extended JSON Formats
30+
---------------------
31+
32+
MongoDB Extended JSON features different string formats to represent
33+
BSON data. Each of the formats conforms to the `JSON RFC
34+
<https://datatracker.ietf.org/doc/html/rfc8259>`__ and meets specific
35+
use cases.
36+
37+
The **Extended** format, also known as the **Canonical**
38+
format, features specific representations for every BSON type for
39+
bidirectional conversion without loss of information. The **Relaxed**
40+
format is more concise and closer to ordinary JSON, but does not
41+
represent all the type information such as the specific byte size of
42+
number fields.
43+
44+
The following table provides descriptions of the JSON formats:
45+
46+
.. list-table::
47+
:header-rows: 1
48+
:stub-columns: 1
49+
:widths: 10 40
50+
51+
* - Name
52+
- Description
53+
54+
* - **Extended**
55+
- | Also known as the *canonical* format, this JSON representation avoids loss of
56+
BSON type information.
57+
| This format prioritizes type preservation at the loss of human-readability and
58+
interoperability with older formats.
59+
60+
* - **Relaxed Mode**
61+
- | JSON representation that describes BSON documents with some type information loss.
62+
| This format prioritizes human-readability and interoperability at the loss of
63+
certain type information.
64+
65+
* - **Shell**
66+
- | JSON representation that matches the syntax used in the MongoDB shell.
67+
| This format prioritizes compatibility with the MongoDB shell, which often uses
68+
JavaScript functions to represent types.
69+
70+
* - **Strict**
71+
- | *Deprecated* This representation is the legacy format that fully conforms to
72+
the JSON RFC and allows any JSON parser to read the type information.
73+
74+
To learn more about JSON, BSON, and Extended JSON, see our
75+
:website:`article about JSON and BSON </resources/basics/json-and-bson>`
76+
and the :manual:`Extended JSON </reference/mongodb-extended-json/>`
77+
reference in the {+mdb-server+} manual.
78+
79+
.. _golang-extended_json_examples:
80+
81+
Extended JSON Examples
82+
~~~~~~~~~~~~~~~~~~~~~~
83+
84+
The following tabs show a document containing an ObjectId, date, and long
85+
number field represented in each Extended JSON format. Select from the
86+
tabs to see the same data presented in each JSON format:
87+
88+
.. tabs::
89+
90+
.. tab:: Extended
91+
:tabid: extended-format
92+
93+
.. code-block:: json
94+
95+
{
96+
"_id": { "$oid": "573a1391f29313caabcd9637" },
97+
"createdAt": { "$date": { "$numberLong": "1601499609" }},
98+
"numViews": { "$numberLong": "36520312" }
99+
}
100+
101+
.. tab:: Relaxed Mode
102+
:tabid: relaxed-mode-format
103+
104+
.. code-block:: json
105+
106+
{
107+
"_id": { "$oid": "573a1391f29313caabcd9637" },
108+
"createdAt": { "$date": "2020-09-30T18:22:51.648Z" },
109+
"numViews": 36520312
110+
}
111+
112+
.. tab:: Shell
113+
:tabid: shell-format
114+
115+
.. code-block:: json
116+
117+
{
118+
"_id": ObjectId("573a1391f29313caabcd9637"),
119+
"createdAt": ISODate("2020-09-30T18:22:51.648Z"),
120+
"numViews": NumberLong("36520312")
121+
}
122+
123+
.. tab:: Strict
124+
:tabid: strict-format
125+
126+
.. code-block:: json
127+
128+
{
129+
"_id": { "$oid": "573a1391f29313caabcd9637" },
130+
"createdAt": { "$date": 1601499609 },
131+
"numViews": { "$numberLong": "36520312" }
132+
}
133+
134+
Read Extended JSON
135+
------------------
136+
137+
You can read an Extended JSON string into a {+language+} struct by
138+
calling the ``bson.UnmarshalExtJSON()`` method. This method parses an
139+
Extended JSON string and stores the result in the specified value parameter.
140+
141+
This example shows how you can read an Extended JSON string
142+
into the following ``Person`` struct:
143+
144+
.. literalinclude:: /includes/data-formats/ejson.go
145+
:start-after: begin-person-struct
146+
:end-before: end-person-struct
147+
:language: go
148+
:dedent:
149+
150+
The following code uses the ``UnmarshalExtJSON()`` method to read an
151+
Extended JSON string and unmarshal the data into an instance of ``Person``:
152+
153+
.. io-code-block::
154+
:copyable: true
155+
156+
.. input:: /includes/data-formats/ejson.go
157+
:start-after: begin-unmarshal
158+
:end-before: end-unmarshal
159+
:language: go
160+
:emphasize-lines: 4
161+
:dedent:
162+
163+
.. output::
164+
:language: none
165+
:visible: false
166+
167+
Go Struct Representation:
168+
{ID:ObjectID("578f6fa2df35c7fbdbaed8c5") Name:Liana Ruiz Age:46 Birthday:569203200000 Address:{Street:500 Slippery Rock Road City:Round Rock State:AR} Hobbies:[cycling baking]}
169+
170+
Write Extended JSON
171+
-------------------
172+
173+
You can produce an Extended JSON string from an instance of a
174+
{+language+} struct by calling the ``bson.MarshalExtJSON()`` method.
175+
The following example creates an Extended JSON string in the Relaxed
176+
format from an instance of ``Person``:
177+
178+
.. io-code-block::
179+
:copyable: true
180+
181+
.. input:: /includes/data-formats/ejson.go
182+
:start-after: begin-marshal
183+
:end-before: end-marshal
184+
:language: go
185+
:emphasize-lines: 10
186+
:dedent:
187+
188+
.. output::
189+
:language: none
190+
:visible: false
191+
192+
Extended JSON Representation:
193+
{"_id":{"$oid":"686688fa7c1a2e75405f4697"},"name":"Matteo Carisi","age":49,"birthday":{"$date":"1975-10-30T00:00:00Z"},"address":{"street":"14a Corner Court","city":"Springfield","state":"IL"},"hobbies":["cooking","birdwatching"]}
194+
195+
The second parameter to ``MarshalExtJSON()`` determines if the output
196+
string is in Canonical (Extended) format or Relaxed format. The
197+
preceding example passes ``false`` as the ``canonical`` parameter, so
198+
the output is Relaxed JSON.
199+
200+
.. note:: Dates Before Epoch Time
201+
202+
When you marshal a date value that is before January 1, 1970,
203+
00:00:00 UTC (Epoch time), it appears as a Unix timestamp in Relaxed
204+
JSON. If the date is after the Epoch time, it appears in a readable
205+
date format.
206+
207+
Format Extended JSON
208+
~~~~~~~~~~~~~~~~~~~~
209+
210+
You can use the ``bson.MarshalExtJSONIndent()`` method to print a
211+
formatted Extended JSON string that includes newlines, prefixes, and
212+
indentation.
213+
214+
The following code uses the ``MarshalExtJSONIndent()`` method to print
215+
the JSON string from the preceding example formatted with two spaces of
216+
indentation:
217+
218+
.. io-code-block::
219+
:copyable: true
220+
221+
.. input:: /includes/data-formats/ejson.go
222+
:start-after: begin-marshal-fmt
223+
:end-before: end-marshal-fmt
224+
:language: go
225+
:emphasize-lines: 10
226+
:dedent:
227+
228+
.. output::
229+
:language: none
230+
:visible: false
231+
232+
{
233+
"_id": {
234+
"$oid": "686688fa7c1a2e75405f4697"
235+
},
236+
"name": "Matteo Carisi",
237+
"age": 49,
238+
"birthday": {
239+
"$date": "1975-10-30T00:00:00Z"
240+
},
241+
"address": {
242+
"street": "14a Corner Court",
243+
"city": "Springfield",
244+
"state": "IL"
245+
},
246+
"hobbies": [
247+
"cooking",
248+
"birdwatching"
249+
]
250+
}
251+
252+
API Documentation
253+
-----------------
254+
255+
To learn more about the methods and types used in this guide, see the
256+
following API documentation:
257+
258+
- `UnmarshalExtJSON() <{+api+}/bson#UnmarshalExtJSON>`__
259+
- `MarshalExtJSON() <{+api+}/bson#MarshalExtJSON>`__
260+
- `MarshalExtJSONIndent() <{+api+}/bson#MarshalExtJSONIndent>`__

source/includes/data-formats/ejson.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"time"
7+
8+
"go.mongodb.org/mongo-driver/v2/bson"
9+
)
10+
11+
// begin-person-struct
12+
type Person struct {
13+
ID bson.ObjectID `bson:"_id"`
14+
Name string
15+
Age int
16+
Birthday bson.DateTime
17+
Address Address
18+
Hobbies []string
19+
}
20+
21+
type Address struct {
22+
Street string
23+
City string
24+
State string
25+
}
26+
27+
// end-person-struct
28+
29+
func main() {
30+
31+
// begin-unmarshal
32+
var extJsonString = "{\"_id\":{\"$oid\":\"578f6fa2df35c7fbdbaed8c5\"},\"name\":\"Liana Ruiz\",\"age\":46,\"birthday\":{\"$date\":\"1988-01-15T00:00:00Z\"},\"address\":{\"street\":\"500 Slippery Rock Road\",\"city\":\"Round Rock\",\"state\":\"AR\"},\"hobbies\":[\"cycling\", \"baking\"]}"
33+
34+
var p Person
35+
err := bson.UnmarshalExtJSON([]byte(extJsonString), false, &p)
36+
if err != nil {
37+
log.Fatal(err)
38+
}
39+
40+
fmt.Printf("Go Struct Representation:\n%+v\n", p)
41+
// end-unmarshal
42+
43+
// begin-marshal
44+
var person = Person{
45+
ID: bson.NewObjectID(),
46+
Name: "Matteo Carisi",
47+
Age: 49,
48+
Birthday: bson.NewDateTimeFromTime(time.Date(1975, 10, 30, 0, 0, 0, 0, time.UTC)),
49+
Address: Address{Street: "14a Corner Court", City: "Springfield", State: "IL"},
50+
Hobbies: []string{"cooking", "birdwatching"},
51+
}
52+
53+
newExtJsonString, err := bson.MarshalExtJSON(person, false, true)
54+
if err != nil {
55+
log.Fatal(err)
56+
}
57+
58+
fmt.Printf("Extended JSON Representation:\n%s\n", newExtJsonString)
59+
// end-marshal
60+
61+
// begin-marshal-fmt
62+
formattedString, err := bson.MarshalExtJSONIndent(person, false, true, "", " ")
63+
if err != nil {
64+
log.Fatal(err)
65+
}
66+
67+
fmt.Printf("%s\n", formattedString)
68+
// end-marshal-fmt
69+
70+
}

0 commit comments

Comments
 (0)