CRUD Operations
CRUD operations are four broad categories of database operations.
Create, Read, Update and Delete. These are represented in MongoDB as Insert, Find, Update and Delete.
While there are more specific types alternatives to Find and Update, we’ll stick to the basics for now.
Create
Insert operations create new entities. When an entity is created, it is uniquely identifier by it’s _id field. This is a mandatory key, therefore always present in your models. If you omit this key, one will be generated for you.
The first step in inserting an entity, is getting the database handle. This has already been described in previous tutorials, so visit those if you’re unsure how to get a database handle.
Create.swift
CRUD-01-Insert-Setup.swiftimport MongoKitten // Replace this as appropriate let connectionString = "mongodb://localhost/my_database" let db = try await MongoDatabase.connect(to: connectionString) let kittens = db["kittens"]Next, define a
Kittenmodel, containing an identifer, name and age. Note that MongoKitten natively supports Date, and a new type - ObjectId.Create.swift
CRUD-02-Insert-Model.swiftimport MongoKitten // Replace this as appropriate let connectionString = "mongodb://localhost/my_database" let db = try await MongoDatabase.connect(to: connectionString) let kittens = db["kittens"] import struct Foundation.Date struct Kitten: Codable { let _id: ObjectId let name: String let age: Date }Create a new Kitten, calling the ObjectId initializer to generate a new id for your Kitten instance.
Create.swift
CRUD-03-Insert-CreateInstance.swiftimport MongoKitten // Replace this as appropriate let connectionString = "mongodb://localhost/my_database" let db = try await MongoDatabase.connect(to: connectionString) let kittens = db["kittens"] import struct Foundation.Date struct Kitten: Codable { let _id: ObjectId let name: String let age: Date } let kitten = Kitten( _id: ObjectId(), name: "Milo", age: Date(timeIntervalSince1970: 1617540152) )Finally, perform an
insertEncodedoperation. This encodes your Codable model to BSON and inserts it into the database.Create.swift
CRUD-04-Insert-Perform.swiftimport MongoKitten // Replace this as appropriate let connectionString = "mongodb://localhost/my_database" let db = try await MongoDatabase.connect(to: connectionString) let kittens = db["kittens"] import struct Foundation.Date struct Kitten: Codable { let _id: ObjectId let name: String let age: Date } let kitten = Kitten( _id: ObjectId(), name: "Milo", age: Date(timeIntervalSince1970: 1617540152) ) try await kittens.insertEncoded(kitten)
Read
Find operations retrieve entities from the database. You can perform a find operation on a collection, or a single document.
First, we’ll try to retrieve a single entity - the one we just inserted.
The findOne operation allows you to read one entity from the collection, matching your query.
MongoKitten has its own operator overloads for helping you build readable queries.
Read.swift
CRUD-05-Find-Instance.swiftstruct Kitten: Codable { let _id: ObjectId let name: String let age: Date } let kitten = Kitten( _id: ObjectId(), name: "Milo", age: Date(timeIntervalSince1970: 1617540152) ) try await kittens.insertEncoded(kitten) func getKitten(byId id: ObjectId) async throws { guard let kitten = try await kittens.findOne("_id" == id, as: Kitten.self) else { struct KittenNotFound: Error {} throw KittenNotFound() } return kitten } let kittenCopy = try await getKitten(byId: kitten._id)You can also find all entities matching your query. You can provide a query, to filter entities of interest. Omitting a filter will return all kittens.
You’ll need to decode kittens manually here. You can do so using the
decode()function.Read.swift
CRUD-06-Find-Many.swiftstruct Kitten: Codable { let _id: ObjectId let name: String let age: Date } let kitten = Kitten( _id: ObjectId(), name: "Milo", age: Date(timeIntervalSince1970: 1617540152) ) try await kittens.insertEncoded(kitten) func getKitten(byId id: ObjectId) async throws { guard let kitten = try await kittens.findOne("_id" == id, as: Kitten.self) else { struct KittenNotFound: Error {} throw KittenNotFound() } return kitten } let kittenCopy = try await getKitten(byId: kitten._id) // Loop over all kittens for try await kitten in kittens.find().decode(Kitten.self) { print(kitten) }If you’re only interested in the kittens’ names, you can use the map function to lazily transform each value.
The query will be executed on demand. Therefore, the cursor only executes once the first result is requested.
Read.swift
CRUD-07-Find-Transform.swiftstruct Kitten: Codable { let _id: ObjectId let name: String let age: Date } let kitten = Kitten( _id: ObjectId(), name: "Milo", age: Date(timeIntervalSince1970: 1617540152) ) try await kittens.insertEncoded(kitten) func getKitten(byId id: ObjectId) async throws { guard let kitten = try await kittens.findOne("_id" == id, as: Kitten.self) else { struct KittenNotFound: Error {} throw KittenNotFound() } return kitten } let kittenCopy = try await getKitten(byId: kitten._id) // Loop over all kittens for try await kitten in kittens.find().decode(Kitten.self) { print(kitten) } // Loop over all kittens' names let lastYear = Date().addingTimeInterval(-(24 * 3600 * 365)) let kittenNames = kittens.find("age" >= lastYear) .decode(Kitten.self) .map(\.name) for try await name in kittenNames { print(name) }
Update
There are a couple of Update operations. Update queries can affect part of the model, using the $set operator.
Alternatively, they can replace the whole model.
First, start the query by calling
updateManyorupdateOne, where updateOne limits amount of updates that can take place to one.Update.swift
CRUD-08-Update-Set.swifttry await users.updateMany( where: "role" == "trial",Next, we’ll need to specify the filter. Only documents that match this filter will be updated.
Update.swift
CRUD-09-Update-SetQuery.swifttry await users.updateMany( where: "role" == "trial"Now, for updating part of a Document, you can use the
settingandunsetarguments. In setting, only fields that are specified will be updated to their new value. You can use MongoDB’s projection or update operators to perform more advanced operations.See the Official Documentation for more information.
Update.swift
CRUD-10-Update-SetDocument.swifttry await users.updateMany( where: "role" == "trial", setting: [ "active": false ] )You can also replace the document as a whole, allowing you to change all values in the model at once.
Update.swift
CRUD-11-Update-Replace.swifttry await users.updateEncoded( where: "_id" == kitten._id, to: kitten )