vapor-docs/3.0/docs/databases/mongodb/bson.md

3.6 KiB

BSON

BSON is a performant (not compact) format for storing data in MongoDB. The BSON module used here is extremely performant and support Codable.

Primitives

MongoDB has a set of supported primitives. At the root of any BSON data lies a Document.

  • Double
  • String
  • Document (Array and Dictionary)
  • ObjectId
  • Bool
  • Int32
  • Int (Int64)
  • Binary
  • Decimal128 (not supported)
  • JavascriptCode
  • Null (not nil)
  • Date (from Foundation)
  • MinKey
  • MaxKey
  • RegularExpression (BSON Type)

Document

Document is a type that comes in two representations. Array and Dictionary-like. You should see Document as [(String, Primitive)].

Array-like Documents ignore the key (String) whilst Dictionary-like Documents require using it. For this reason, both Document variants are the same struct type and behave the same way.

You can subscript a dictionary-like document with an integer, and an array-like document by it's key.

Usage

The root type of any BSON structure is a Document, please note that MongoDB entities must be a dictionary-like.

To create a dictionary-like BSON Document:

// Dictionary document by default
var document = Document()

You can also use a dictionary or array literal. This creates the respective BSON document type.

var arrayDocument: Document = []
var dictionaryDocument: Document = [:]

Accessing Dictionary Documents

To access a dictionary document you must subscript with a key:

let username = dictionaryDocument["username"] // Primitive?

The return type is a Primitive type, which is a protocol.

Accessing Array Documents

To a

Primitives

To access the concrete type of the primitive you must either cast the primitive to a concrete type or loosely unwrap the type.

For the purpose of demonstration we're assuming the following Document:

var doc: Document = [
    "_id": ObjectId(),
    "username": "Joannis",
    "admin": true,
    "year": 2018
]

Casting

Casting is used when you want exactly that type. A good example is a String.

let username = doc["username"] as? String // String?
print(username) // Optional("Joannis")

The following will be nil because they're not a String.

let _id: = doc["_id"] as? String // String?
print(_id) // nil

let admin = doc["admin"] as? String // String?
print(admin) // nil

let year = doc["year"] as? String // String?
print(year) // nil

Loosely Converting

Converting is useful when you don't care about the specifics. For example, when exposing data over JSON.

let username = String(lossy: doc["username"]) // String?
print(username) // Optional("Joannis")

This converts types to a String when it's sensible:

let _id: = doc["_id"] as? String // String?
print(_id) // Optional("afafafafafafafafafafafaf")

let admin = doc["admin"] as? String // String?
print(admin) // Optional("true")

let year = doc["year"] as? String // String?
print(year) // Optional("2018")

Codable

BSON has highly optimized support for Codable through BSONEncoder and BSONDecoder.

struct User: Codable {
    var _id = ObjectId()
    var username: String
    var admin: Bool = false
    var year: Int

    init(named name: String, year: Int) {
        self.username = name
        self.year = year
    }
}

let user = User(named: "Joannis", year: 2018)

let userDocument = try BSONEncoder().encode(user)

let username = userDocument["username"] as? String
print(username) // Optional("Joannis")

let sameUser = try BSONDecoder().decode(User.self, from: userDocument)

print(sameUser.username) // "Joannis"