0% completed
Introduction to BSON
On This Page
Reading the Bytes
A Date Takes Less Space Than Its Text
BSON Is Not Always Smaller
BSON Data Types
Converting BSON Back to Text
BSON and JSON Compared
The same user takes 112 characters as JSON text and 96 bytes in the binary form that MongoDB uses. Here is the JSON text:
{"name":"John Doe","age":30,"email":"john.doe@example.com","isStudent":false,"createdAt":"2023-06-01T00:00:00Z"}
MongoDB does not store that text. It stores a binary encoding of the document, with a tag on each value that states its type. This format is called BSON, which stands for Binary JSON. It is used both to store documents on the server and to send them over the network, and it adds types that JSON does not have.
As a result, you normally never see BSON. You work with readable objects, and the driver (the library that connects your program or mongosh to the server) converts them in both directions.
Reading the Bytes
A short document shows how the format works. This user has three fields, and in BSON it takes 45 bytes:
{ name: "John Doe", age: 30, isStudent: false }
2d 00 00 00 total size: 45 bytes 02 6e 61 6d 65 00 type 02 (string), field name "name" 09 00 00 00 4a 6f 68 6e 20 44 6f 65 00 length 9, then "John Doe" and a null byte 10 61 67 65 00 type 10 (32-bit integer), field name "age" 1e 00 00 00 value 30 08 69 73 53 74 75 64 65 6e 74 00 type 08 (Boolean), field name "isStudent" 00 value false 00 end of document
Each number here is stored in binary, with the least significant byte first, which is why 45 appears as 2d 00 00 00. As a 32-bit integer, 30 takes four bytes, and reading it needs no conversion from text.
Now look at the length stored in front of "John Doe". Suppose MongoDB needs the isStudent field from this document. It reads the type and name of name, sees that the value is 9 bytes long, and skips those bytes without reading them. A JSON parser cannot do this, because it must read each character to find where a string ends. Moving through a document in this way is called traversal, and fast traversal is one of the main goals of BSON.
A Date Takes Less Space Than Its Text
The 96 bytes at the start of this lesson depend on one choice: createdAt was stored as a real date, using new Date("2023-06-01T00:00:00Z"). A BSON date takes 8 bytes. If you insert the same value as a string, the document takes 113 bytes, because the string needs 21 bytes for its characters and its final null byte, and 4 more for its length.
The size is the smaller benefit. A value stored with the date type sorts and compares as a date, whereas a string can only compare as text.
BSON Is Not Always Smaller
It would be wrong to conclude that BSON always saves space. The length prefixes and type tags take room, and small values can become larger than their text form. These counts come from encoding each document with a BSON library and measuring the JSON text:
| Document | JSON characters | BSON bytes |
|---|---|---|
{"age":30} | 10 | 14 |
{"scores":[1,2,3]} | 18 | 39 |
{"n":2147483647} | 16 | 12 |
| The user above, with a real date | 112 | 96 |
The array is the clearest case. BSON stores an array as a document whose field names are the positions "0", "1" and "2", and each small number therefore costs seven bytes. A stored document also has an _id field, which adds 17 bytes when it holds a generated identifier. The 96-byte user therefore takes 113 bytes once it is inserted, and the match with the string figure above is only a coincidence.
BSON accepts this extra space because the goal is speed. Binary numbers need no parsing, and the stored lengths allow skipping. The BSON specification itself says that BSON can use more space than JSON.
BSON Data Types
These are the types you can meet in a MongoDB document. The alias is the name that MongoDB uses for the type in queries and in the output of $type.
| Data Type | Alias | Description |
|---|---|---|
| String | string | UTF-8 text. |
| 32-bit Integer | int | A signed whole number stored in 4 bytes. |
| 64-bit Integer | long | A signed whole number stored in 8 bytes. |
| Double | double | A 64-bit floating point number, which can hold fractions but stores most of them approximately. |
| Decimal128 | decimal | A 128-bit decimal floating point number. |
| Boolean | bool | true or false. |
| Null | null | A null value. |
| Array | array | An ordered list of values. |
| Object | object | A nested document. |
| Binary Data | binData | An array of bytes. |
| ObjectId | objectId | A 12-byte identifier, usually for _id. |
| Date | date | Milliseconds since January 1, 1970 (the Unix epoch), in 8 bytes. |
| Regular Expression | regex | A regular expression pattern. |
| JavaScript | javascript | JavaScript code stored as text. |
| JavaScript with Scope | javascriptWithScope | JavaScript code with a set of variables. Deprecated. |
| Timestamp | timestamp | A special timestamp for internal MongoDB use. |
| Min Key | minKey | A value that compares lower than all other values. |
| Max Key | maxKey | A value that compares higher than all other values. |
Three further types exist only for old data, and all three are deprecated: undefined, dbPointer and symbol.
Converting BSON Back to Text
Plain JSON cannot represent these extra types, and a date becomes a plain string when it is converted, with its type lost. MongoDB therefore has an extended form of JSON that records the type inside the text. In mongosh, EJSON.stringify produces it:
EJSON.stringify({ name: "John Doe", createdAt: new Date("2023-06-01T00:00:00Z") })
{"name":"John Doe","createdAt":{"$date":"2023-06-01T00:00:00Z"}}
The result is still valid JSON, and a program that understands this form can restore the date.
BSON and JSON Compared
| Aspect | BSON | JSON |
|---|---|---|
| Format | Binary | Text |
| Size | Larger or smaller than the JSON text, because of type tags, lengths and binary values | One character for each character of text |
| Encoding and decoding | Fast: numbers need no parsing | Slower: all values must be parsed from text |
| Data types | Adds dates, binary data, several number types and more | Six types only |
| Traversal | Lengths allow a reader to skip values | A reader must read each character |
| Human readability | Needs a tool to read | Readable directly |
Reading Progress
0%
On This Page
Reading the Bytes
A Date Takes Less Space Than Its Text
BSON Is Not Always Smaller
BSON Data Types
Converting BSON Back to Text
BSON and JSON Compared