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"