Unit Grijjy.Bson

DescriptionUsesClasses, Interfaces, Objects and RecordsFunctions and ProceduresTypesConstantsVariables

Description

A light-weight and fast BSON and JSON object model, with support for efficiently parsing and writing in JSON and BSON format.

The code in this unit is fully compatible with the BSON and JSON used by MongoDB. It supports all JSON extensions used by MongoDB.

However, this unit does not have any dependencies on the MongoDB units and can be used as a stand-alone BSON/JSON library. It is therefore also suitable as a general purpose JSON library.

Quick Start

  var
    Doc: TgoBsonDocument;
    A: TgoBsonArray;
    Json: String;
    Bson: TBytes;
  begin
    Doc := TgoBsonDocument.Create;
    Doc.Add('Hello', 'World');

    A := TgoBsonArray.Create(['awesome', 5.05, 1986]);
    Doc.Add('BSON', A);

    Json := Doc.ToJson; // Returns:
    // { "hello" : "world",
    //   "BSON": ["awesone", 5.05, 1986] }

    Bson := Doc.ToBson; // Saves to binary BSON

    Doc := TgoBsonDocument.Parse('{ "Answer" : 42 }');
    WriteLn(Doc['Answer']); // Outputs 42
    Doc['Answer'] := 'Unknown';
    Doc['Pi'] := 3.14;
    WriteLn(Doc.ToJson); // Outputs { "Answer" : "Unknown", "Pi" : 3.14 }
  end;

Object Model

The root type in the BSON object model is TgoBsonValue. TgoBsonValue is a record type which can hold any type of BSON value. Some implicit class operators make it easy to assign basic types:

  var
    Value: TgoBsonValue;
  begin
    Value := True;                           // Creates a Boolean value
    Value := 1;                              // Creates an Integer value
    Value := 3.14;                           // Creates a Double value
    Value := 'Foo';                          // Creates a String value
    Value := TBytes.Create(1, 2, 3);         // Creates a binary (TBytes) value
    Value := TgoObjectId.GenerateNewId;      // Creates an ObjectId value
  end;

Note that you can change the type later by assigning a value of another type. You can also go the other way around:

  var
    Value: TgoBsonValue;
    FloatVal: Double;
  begin
    Value := 3.14;              // Creates a Double value
    FloatVal := Value;          // Uses implicit cast
    FloatVal := Value.AsDouble; // Or more explicit cast
    Value := 42;                // Creates an Integer value
    FloatVal := Value;          // Converts an Integer BSON value to a Double
    FloatVal := Value.AsDouble; // Raises exception because types don't match exactly

    if (Value.BsonType = TgoBsonType.Double) then
      FloatVal := Value.AsDouble; // Now it is safe to cast

    // Or identical:
    if (Value.IsDouble) then
      FloatVal := Value.AsDouble;
  end;

Note that the implicit operators will try to convert if the types don't match exactly. For example, a BSON value containing an Integer value can be implicitly converted to a Double. If the conversion fails, it returns a zero value (or empty string).

The "As*" methods however will raise an exception if the types don't match exactly. You should use these methods if you know that the type you request matches the value's type exactly. These methods are a bit more efficient than the implicit operators.

You can check the value type using the BsonType-property or one of the "Is*" methods.

For non-basic types, there are value types that are "derived" from TgoBsonValue:

  • TgoBsonNull: the special "null" value

  • TgoBsonArray: an array of other BSON values.

  • TgoBsonDocument: a document containing key/value pairs, where the key is a string and the value can be any BSON value. This is usually the main starting point in Mongo, since all database "records" are represented as BSON documents in Mongo. A document is similar to a dictionary in many programming languages, or the "object" type in JSON.

  • TgoBsonBinaryData: arbitrary binary data. Is also used to store GUID's (but not ObjectId's).

  • TgoBsonDateTime: a date/time value with support for conversion to and from UTC (Universal) time. Is always stored in UTC format (as the number of UTC milliseconds since the Unix epoch).

  • TgoBsonRegularExpression: a regular expression with options.

  • TgoBsonJavaScript: a piece of JavaScript code.

  • TgoBsonJavaScriptWithScope: a piece of JavaScript code with a scope (a set of variables with values, as defined in another document).

  • TgoBsonTimestamp: special internal type used by MongoDB replication and sharding.

  • TgoBsonMaxKey: special type which compares higher than all other possible BSON element values.

  • TgoBsonMinKey: special type which compares lower than all other possible BSON element values.

  • TgoBsonUndefined: an undefined value (deprecated by BSON)

  • TgoBsonSymbol: a symbol from a lookup table (deprecated by BSON)

Note that these are not "real" derived types, since they are implemented as Delphi records (which do not support inheritance). But the implicit operators make it possible to treat each of these types as a TgoBsonValue. For example

  var
    MyArray: TgoBsonArray;
    Value: TgoBsonValue;
  begin
    MyArray := TgoBsonArray.Create([1, 3.14, 'Foo', False]);
    Value := MyArray; // "subtypes" are compatible with TgoBsonValue

    // Or shorter:
    Value := TgoBsonArray.Create([1, 3.14, 'Foo', False]);
  end;

Arrays

The example above also shows that arrays can be created very easily. An array contains a collection of BSON values of any type. Since BSON values can be implicitly created from basic types, you can pass multiple types in the array constructor. In the example above, 4 BSON values will be added to the array of types Integer, Double, String and Boolean.

You can also add items using the Add or AddRange methods:

  MyArray := TgoBsonArray.Create;
  MyArray.Add(1);
  MyArray.Add(3.14);
  MyArray.Add('Foo');

Some methods return the array (or document) itself, so they can be used for chaining (aka as a "fluent interface"). The example above is equivalent to:

  MyArray := TgoBsonArray.Create;
  MyArray.Add(1).Add(3.14).Add('Foo');

You can change values (and types) like this:

  // Changes entry 1 from Double to Boolean
  MyArray[1] := True;

Documents

Documents (or dictionaries) can also be created easily:

  var
    Doc: TgoBsonDocument;
  begin
    Doc := TgoBsonDocument.Create('Answer', 42);
  end;

This creates a document with a single entry called 'Answer' with a value of 42. Keep in mind that the value can be any BSON type:

  Doc := TgoBsonDocument.Create('Answer', TgoBsonArray.Create([42, False]));

You can Add, Remove and Delete (Adds can be fluent):

  Doc := TgoBsonDocument.Create;
  Doc.Add('Answer', 42);
  Doc.Add('Pi', 3.14).Add('Pie', 'Yummi');

  // Deletes second item (Pi):
  Doc.Delete(1);

  // Removes first item (Answer):
  Doc.Remove('Answer');

Like Delphi dictionaries, the Add method will raise an exception if an item with the given name already exists. Unlike Delphi dictionaries however, you can easily set an item using its default accessor:

  // Adds Answer:
  Doc['Answer'] := 42;

  // Adds Pi:
  Doc['Pi'] := 3.14;

  // Updates Answer:
  Doc['Answer'] := 'Everything';

This adds the item if it does not yet exists, or replaces it otherwise (there is no (need for an) AddOrSet method).

Also unlike Delphi dictionaries, documents maintain insertion order and you can also access the items by index:

  // Returns item by name:
  V := Doc['Pi'];

  // Returns item by index:
  V := Doc.Values[1];

Documents can be easily parsed from JSON:

  Doc := TgoBsonDocument.Parse('{ "Answer" : 42 }');

The parser understands standard JSON as well as the MongoDB JSON extensions.

You can also load a document from a BSON byte array:

  Bytes := LoadSomeBSONData();
  Doc := TgoBsonDocument.Load(Bytes);

These methods will raise exceptions if the JSON or BSON data is invalid.

Memory Management

All memory management in this library is automatic. You never need to (and you never must) destroy any objects yourself.

The object model types (TgoBsonValue and friends) are all Delphi records. The actual implementations of these records use interfaces to manage memory.

There is no concept of ownership in the object model. An array does not own its elements and a document does not own its elements. So you are free to add the same value to multiple arrays and/or documents without ownership concerns:

  var
    Array1, Array2, SubArray, Doc1, Doc2: TgoBsonValue;
  begin
    SubArray := TgoBsonArray.Create([42, 'Foo', True]);
    Array1 := TgoBsonArray.Create;
    Array2 := TgoBsonArray.Create([123, 'Abc']);
    Doc1 := TgoBsonDocument.Create;
    Doc2 := TgoBsonDocument.Create('Pi', 3.14);

    Array1.Add(SubArray);
    Array2.Add(SubArray);      // Add same value to other container
    Doc1.Add('Bar', SubArray); // And again
    Doc2.Add('Baz', SubArray); // And again
  end;

Non-object model types are defined as interfaces, so their memory is managed automatically as well. For example JSON/BSON readers and writer are interfaces:

  var
    Reader: IgoJsonReader;
    Value: TgoBsonValue;
  begin
    Reader := TgoJsonReader.Create('{ "Pi" : 3.14 }');
    Value := Reader.ReadValue;
    Assert(Value.IsDocument);
    Assert(Value.AsDocument['Pi'] = 3.14);
  end;

Just keep in mind that you must always declare your variable (Reader) as an interface type (IgoJsonReader), but you construct it using the class type (TgoJsonReader).

JSON and BSON reading and writing

For easy storing, all BSON values have methods called ToJson and ToBson to store its value into JSON or BSON format:

  var
    A: TgoBsonValue;
    B: TBytes;
  begin
    A := 42;
    WriteLn(A.ToJson); // Outputs '42'

    A := 'Foo';
    WriteLn(A.ToJson); // Outputs '"Foo"'

    A := TgoBsonArray.Create([1, 'Foo', True]);
    WriteLn(A.ToJson); // Outputs '[1, "Foo", true]'

    A := TgoBsonDocument.Create('Pi', 3.14);
    WriteLn(A.ToJson); // Outputs '{ "Pi" : 3.14 }'
    B := A.ToBson;     // Outputs document in BSON format
  end;

When outputting to JSON, you can optionally supply a settings record to customize the output:

  • Whether to pretty-print the output

  • What strings to use for indentation and line breaks

  • Whether to output standard JSON or use the MongoDB shell syntax extension

If you don's supply any settings, then output will be in Strict JSON format without pretty printing.

Easy loading is only supported at the Value, Document and Array level, using the Parse and Load methods:

  var
    Doc: TgoBsonDocument;
    Bytes: TBytes;
  begin
    Doc := TgoBsonDocument.Parse('{ "Pi" : 3.14 }');
    Bytes := LoadSomeBSONData();
    Doc := TgoBsonDocument.Load(Bytes);
  end;

You can load other types using the IgoJsonReader and IgoBsonReader interfaces:

  var
    Reader: IgoBsonReader;
    Value: TgoBsonValue;
    Bytes: TBytes;
  begin
    Bytes := LoadSomeBSONData();
    Reader := TgoBsonReader.Create(Bytes);
    Value := Reader.ReadValue;
  end;

The JSON reader and writer supports both the "strict" JSON syntax, as well as the "Mongo Shell" syntax (see https://docs.mongodb.org/manual/reference/mongodb-extended-json/). Extended JSON is supported for both reading and writing. This library supports all the current extensions, as well as some deprecated legacy extensions. The JSON reader accepts both key names with double quotes (as per JSON spec) as without quotes.

Manual reading and writing

For all situations, the methods ToJson, ToBson, Parse and Load can take care of reading and writing any kind of JSON and BSON data.

However, you can use the reading and writing interfaces directly if you want for some reason. One reason may be that you want the fastest performance when creating BSON payloads, without the overhead of creating a document object model in memory.

For information, see the unit Grijjy.Data.Bson.IO

Serialization

For even easier reading and writing, you can use serialization to directory store a Delphi record or object in JSON or BSON format (or convert it to a TgoBsonDocument).

For information, see the unit Grijjy.Data.Bson.Serialization

Overview

Classes, Interfaces, Objects and Records

Name Description
record TgoJsonWriterSettings Settings for a IgoJsonWriter
record TgoObjectId Represents an ObjectId.
record TgoBsonValue The base "class" for all BSON values.
record TgoBsonArray An array of other BSON values
record TgoBsonElement An element in a TgoBsonDocument
record TgoBsonDocument A BSON document.
record TgoBsonBinaryData A blob of binary data
record TgoBsonNull Represents the BSON Null value
record TgoBsonUndefined Represents the BSON Undefined value
record TgoBsonDateTime A BSON DateTime value
record TgoBsonTimestamp A BSON Timestamp.
record TgoBsonRegularExpression A BSON Regular Expression
record TgoBsonJavaScript A piece of JavaScript code
record TgoBsonJavaScriptWithScope A piece of JavaScript code with a scope (a set of variables with values, as defined in another document).
record TgoBsonSymbol A symbol from a lookup table (deprecated by BSON).
record TgoBsonSymbolTable A table used to lookup TgoBsonSymbol values
record TgoBsonMaxKey Represents the BSON MaxKey value
record TgoBsonMinKey Represents the BSON MinKey value
record TgoBsonValueHelper Adds methods to TgoBsonValue

Types

TgoBsonType = (...);
TgoBsonBinarySubType = (...);
TgoJsonOutputMode = (...);
PgoObjectId = ˆTgoObjectId;

Description

Types

TgoBsonType = (...);

Supported BSON types. As returned by TgoBsonValue.BsonType. Tech note: Ordinal values must match BSON spec (http://bsonspec.org)

Values
  • EndOfDocument = $00: Not a real BSON type. Used to signal the end of a document.
  • Double = $01: A BSON double
  • String = $02: A BSON string
  • Document = $03: A BSON document (see TgoBsonDocument)
  • Array = $04: A BSON array (see TgoBsonArray)
  • Binary = $05: BSON binary data (see TgoBsonBinaryData)
  • Undefined = $06: A BSON undefined value (see TgoBsonUndefined)
  • ObjectId = $07: A ObjectId, generally used with MongoDB (see TgoObjectId)
  • Boolean = $08: A BSON boolean
  • DateTime = $09: A BSON DateTime (see TgoBsonDateTime)
  • Null = $0A: A BSON null value (see TgoBsonNull)
  • RegularExpression = $0B: A BSON regular expression (see TgoBsonRegularExpression)
  • JavaScript = $0D: BSON JavaScript code (see TgoBsonJavaScript)
  • Symbol = $0E: A BSON Symbol (see TgoBsonSymbol, deprecated)
  • JavaScriptWithScope = $0F: BSON JavaScript code with a scope (see TgoBsonJavaScriptWithScope)
  • Int32 = $10: A BSON 32-bit integer
  • Timestamp = $11: A BSON Timestamp (see TgoBsonTimestamp)
  • Int64 = $12: A BSON 64-bit integer
  • MaxKey = $7F: A BSON MaxKey value (see TgoBsonMaxKey)
  • MinKey = $FF: A BSON MinKey value (see TgoBsonMinKey)
TgoBsonBinarySubType = (...);

Supported BSON binary sub types. As returned by TgoBsonBinaryData.SubType. Tech note: Ordinal values must match BSON spec (http://bsonspec.org)

Values
  • Binary = $00: Binary data in an arbitrary format
  • Function = $01: A function
  • OldBinary = $02: Obsolete binary type
  • UuidLegacy = $03: A UUID/GUID in driver dependent legacy byte order
  • UuidStandard = $04: A UUID/GUID in standard network byte order (big endian)
  • MD5 = $05: A MD5 hash
  • UserDefined = $80: User defined type
TgoJsonOutputMode = (...);

The output mode of a IgoJsonWriter, as set using TgoJsonWriterSettings.

Values
  • Strict: Outputs strict JSON
  • Shell: Outputs a format that can be used by the MongoDB shell
PgoObjectId = ˆTgoObjectId;
 

Generated by P2PasDoc 0.13.0 on 2017-04-25 12:54:26