class

BSON

Inherits Comparable < Iterable < Enumerable < Reference < Object

BSON is a binary format in which zero or more ordered key/value pairs are stored as a single entity.

BSON [bee ยท sahn], short for Binary JSON, is a binary-encoded serialization of JSON-like documents. Like JSON, BSON supports the embedding of documents and arrays within other documents and arrays. BSON also contains extensions that allow representation of data types that are not part of the JSON spec. For example, BSON has a Date type and a BinData type.

See: http://bsonspec.org/

require "bson"

data = BSON.new({
  hello: "world",
  time:  Time.utc,
  name:  BSON.new({
    first_name: "John",
    last_name:  "Doe",
  }),
  fruits: ["Orange", "Banana"],
})

puts data.to_json
# => {"hello":"world","time":{"$date":"2020-05-18T07:32:13.621000000Z"},"name":{"first_name":"John","last_name":"Doe"},"fruits":["Orange","Banana"]}

Heap class so Crystal 1.21 GC scans @data (Wave 58). A struct whose @data is an interior Slice is not a Darwin GC root after OwnedReceive#view returns (33990243466 macos-15 standalone SIGBUS). BSON.view still does not copy bytes. ObjectId / Binary / Decimal128 stay structs.

Constructors

build

Build a document in one pass. Prefer this in Cryomongo instead of many []= calls.

Source
new(data : Bytes | Nil = nil, validate : Bool = false)

Allocate a BSON instance from a byte array.

NOTE: The byte array is cloned.

data = "160000000378000E0000000261000200000062000000".hexbytes
io = IO::Memory.new(data)
bson = BSON.new(io)
puts bson.to_json # => {"x":{"a":"b"}}
Source
new(io : IO)

Allocate a BSON instance from an IO

data = "160000000378000E0000000261000200000062000000".hexbytes
bson = BSON.new(data)
puts bson.to_json # => {"x":{"a":"b"}}
Source
new(tuple : NamedTuple)

Allocate a BSON instance from a NamedTuple.

puts BSON.new({
  hello: "world",
}).to_json # => {"hello":"world"}
Source
new(h : Hash)

Allocate a BSON instance from a Hash.

puts BSON.new({
  "hello" => "world",
}).to_json # => {"hello":"world"}
Source
new(bson : BSON)

No-op

Source
new(ary : Array)

Allocate a BSON instance from an Array.

puts BSON.new([1, 2, 3]).to_json # => [1,2,3]
Source
new(serializable : BSON::Serializable)

Allocate a BSON instance from an instance of BSON::Serializable.

Source
parse(data : Bytes) : self

Read data and walk every field. Raises BSON::Error when the document is invalid.

Source
view(data : Bytes, validate : Bool = false) : self

Create a BSON document over data without copying the bytes.

One heap object. @data is a Slice the GC scans. Do not copy bytes a second time. The slice must stay valid for the life of the document. Nested values decoded from a parent document use this path.

Source

Class methods

from_io?(io : IO) : self | Nil

Read a document from io. Returns nil when the bytes are invalid or short.

Source
from_json(json : String)

Allocate a BSON instance from a relaxed extended json representation.

NOTE: see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst

bson = BSON.from_json(%({
  "_id": {
    "$oid": "57e193d7a9cc81b4027498b5"
  },
  "String": "string",
  "Int": 42,
  "Double": -1.0
}))
puts bson.to_json # => {"_id":{"$oid":"57e193d7a9cc81b4027498b5"},"String":"string","Int":42,"Double":-1.0}
Source
from_json?(json : String) : self | Nil

Parse Extended JSON. Returns nil when the text is not valid BSON ExtJSON.

Source
parse?(data : Bytes) : self | Nil

Read data and walk every field. Returns nil when the document is invalid.

Source

Instance methods

<=>(other : BSON)

Compare with another BSON value.

puts BSON.new({a: 1}) <=> BSON.new({a: 1}) # => 0
puts BSON.new({a: 1}) <=> BSON.new({b: 2}) # => -1
Source
[](key : String | ::Symbol) : Value

Return the element with the given key.

NOTE: Will raise if the key is not found.

bson = BSON.new({ key: "value" })
puts bson["key"] # =>"value"
puts bson["nope"] # => Unhandled exception: Missing bson key: nope (KeyError)
Source
[]=(key : String | ::Symbol, value)

Append a key/value pair.

bson = BSON.new
bson["key"] = "value"
puts bson.to_json # => {"key":"value"}
Source
[]?(key : String | ::Symbol) : Value | Nil

Return the element with the given key, or nil if the key is not present.

bson = BSON.new({key: "value"})
puts bson["key"]?  # => "value"
puts bson["nope"]? # => nil
Source
append(other : BSON)

Append the contents of another BSON instance.

bson = BSON.new
other_bson = BSON.new({key: "value", key2: "value2"})
bson.append(other_bson)
puts bson.to_json # => {"key":"value","key2":"value2"}
Source
append

Append one or more key/value pairs.

NOTE: more efficient for appending multiple values than calling []= individually.

bson = BSON.new
bson.append(key: "value", key2: "value2")
puts bson.to_json # => {"key":"value","key2":"value2"}
Source
append

Append several fields with one rebuild of the document buffer.

Source
append_array(key : String | ::Symbol, value : BSON)

Append a key/value pair and declare it as a BSON array.

Source
canonicalize

Re-encode this document from decoded values.

Degenerate array keys become 0, 1, 2, ... and regex options become alphabetical. Used to check native BSON round-trips.

Source
clear

Clears the BSON instance.

Source
data

Underlying bytes

Source
dig(key : String | ::Symbol, *subkeys)

Traverses the depth of a structure and returns the value, otherwise raises.

Source
dig?(key : String | ::Symbol, *subkeys)

Traverses the depth of a structure and returns the value. Returns nil if not found.

Source
each

Yield each key/value pair to the block.

NOTE: Underlying BSON code as well as the binary subtype are also yielded to the block as additional arguments.

BSON.new({
  a: 1,
  b: "2",
  c: Slice[0_u8, 1_u8, 2_u8],
}).each { |(key, value, code, binary_subtype)|
  puts "#{key} => #{value}, code: #{code}, subtype: #{binary_subtype}"
# a => 1, code: Int32, subtype:
# b => 2, code: String, subtype:
# c => Bytes[0, 1, 2], code: Binary, subtype: Generic
}
Source
each

Returns an Iterator over each key/value pair.

Source
empty?

Returns true if the BSON is empty.

Source
has_key?(key : String | ::Symbol) : Bool

Returns true when key given by key exists, otherwise false.

Source
size

Return the size of the BSON instance in bytes.

Source
to_canonical_extjson

Serialize this BSON instance into a canonical extended json representation.

NOTE: see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst

bson = BSON.from_json(%({
  "Int": 42,
  "Double": -1.0
}))
puts bson.to_canonical_extjson # => {"Int":{"$numberLong":"42"},"Double":{"$numberDouble":"-1.0"}}
Source
to_h

Returns a Hash representation.

NOTE: This function is recursive and will convert nested BSON to hash objects.

bson = BSON.new({
  a: 1,
  b: "2",
  c: {
    d: 1,
  },
})
pp bson.to_h # => {"a" => 1, "b" => "2", "c" => { "d" => 1}}
Source
to_json(builder : JSON::Builder, *, array = false)

ameba:disable Metrics/CyclomaticComplexity

Source
validate!

Validate that the BSON is well-formed.

bson = BSON.new("140000000461000D0000001030000A0000000000".hexbytes)
bson.validate!
# => Unhandled exception: Invalid BSON (overflow) (Exception)
Source

Nested types