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

156 lines
3.6 KiB
Markdown

# 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:
```swift
// Dictionary document by default
var document = Document()
```
You can also use a dictionary or array literal. This creates the respective BSON document type.
```swift
var arrayDocument: Document = []
var dictionaryDocument: Document = [:]
```
## Accessing Dictionary Documents
To access a dictionary document you must subscript with a key:
```swift
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:
```swift
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`.
```swift
let username = doc["username"] as? String // String?
print(username) // Optional("Joannis")
```
The following will be nil because they're not a `String`.
```swift
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.
```swift
let username = String(lossy: doc["username"]) // String?
print(username) // Optional("Joannis")
```
This converts types to a String when it's sensible:
```swift
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`.
```swift
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"
```