Skip to content

Commit 18a20bf

Browse files
SWIFT-423 Provide transactions guide for docs (#444)
1 parent 2545db0 commit 18a20bf

File tree

3 files changed

+168
-1
lines changed

3 files changed

+168
-1
lines changed

Examples/Docs/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import PackageDescription
44
let package = Package(
55
name: "DocsExamples",
66
dependencies: [
7-
.package(url: "https://github.com/mongodb/mongo-swift-driver", .upToNextMajor(from: "1.0.0-rc0")),
7+
.package(url: "https://github.com/mongodb/mongo-swift-driver", .branch("master")),
88
.package(url: "https://github.com/apple/swift-nio", .upToNextMajor(from: "2.0.0"))
99
],
1010
targets: [

Examples/Docs/Sources/AsyncExamples/main.swift

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,80 @@ private func changeStreams() throws {
147147
// End Changestream Example 4
148148
}
149149
}
150+
151+
/// Examples used for the MongoDB documentation on Transactions.
152+
/// - SeeAlso: https://docs.mongodb.com/manual/core/transactions/
153+
private func transactions() throws {
154+
let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1)
155+
let client = try MongoClient(using: elg)
156+
let session = client.startSession()
157+
158+
defer {
159+
client.syncShutdown()
160+
cleanupMongoSwift()
161+
try? elg.syncShutdownGracefully()
162+
}
163+
164+
do {
165+
// Start Transactions Example 1
166+
let db = client.db("test")
167+
let srcColl = db.collection("src")
168+
let destColl = db.collection("coll")
169+
let docToMove: Document = ["hello": "world"]
170+
171+
session.startTransaction().flatMap { _ in
172+
srcColl.deleteOne(docToMove, session: session)
173+
}.flatMap { _ in
174+
destColl.insertOne(docToMove, session: session)
175+
}.flatMap { _ in
176+
session.commitTransaction()
177+
}.whenFailure { _ in
178+
session.abortTransaction()
179+
// handle error
180+
}
181+
// End Transactions Example 1
182+
}
183+
184+
do {
185+
// Start Transactions Example 2
186+
let txnOpts = TransactionOptions(
187+
maxCommitTimeMS: 30,
188+
readConcern: ReadConcern(.local),
189+
readPreference: .primaryPreferred,
190+
writeConcern: try WriteConcern(w: .majority)
191+
)
192+
193+
session.startTransaction(options: txnOpts).flatMap { _ in
194+
// do something
195+
}.flatMap { _ in
196+
session.commitTransaction()
197+
}.whenFailure { _ in
198+
session.abortTransaction()
199+
// handle error
200+
}
201+
// End Transactions Example 2
202+
}
203+
204+
do {
205+
// Start Transactions Example 3
206+
let txnOpts = TransactionOptions(
207+
maxCommitTimeMS: 30,
208+
readConcern: ReadConcern(.local),
209+
readPreference: .primaryPreferred,
210+
writeConcern: try WriteConcern(w: .majority)
211+
)
212+
213+
let client = try MongoClient(using: elg)
214+
let session = client.startSession(options: ClientSessionOptions(defaultTransactionOptions: txnOpts))
215+
216+
session.startTransaction().flatMap { _ in
217+
// do something
218+
}.flatMap { _ in
219+
session.commitTransaction()
220+
}.whenFailure { _ in
221+
session.abortTransaction()
222+
// handle error
223+
}
224+
// End Transactions Example 3
225+
}
226+
}

Guides/Transactions.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Swift Driver Transactions Guide
2+
3+
`MongoSwift` 1.0.0 added support for [transactions](https://docs.mongodb.com/manual/core/transactions/), which allow applications to use to execute multiple read and write operations atomically across multiple documents and/or collections. Transactions reduce the need for complicated application logic when operating on several different documents simultaneously; however, because operations on single documents are always atomic, transactions are often not necessary.
4+
5+
Transactions in the driver must be started on a `ClientSession` using `startTransaction()`. The session must then be passed to each operation in the transaction. If the session is not passed to an operation, said operation will be executed outside the context of the transaction. Transactions must be committed or aborted using `commitTransaction()` or `abortTransaction()`, respectively. Ending a session *aborts* all in-progress transactions.
6+
7+
**Note**: Transactions only work with MongoDB replica sets (v4.0+) and sharded clusters (v4.2+).
8+
9+
## Examples
10+
11+
### Transaction that Atomically Moves a `Document` from One `MongoCollection` to Another
12+
13+
The transaction below atomically deletes the document `{ "hello": "world" }` from the collection `test.src` and inserts the document in the collection `test.dest`. This ensures that the document exists in either `test.src` or `test.dest`, but not both or neither. Executing the delete and insert non-atomically raises the following issues:
14+
- A race between `deleteOne()` and `insertOne()` where the document does not exist in either collection.
15+
- If `deleteOne()` fails and `insertOne()` succeeds, the document exists in both collections.
16+
- If `deleteOne()` succeeds and `insertOne()` fails, the document does not exist in either collection.
17+
18+
```swift
19+
let client = try MongoClient(using: elg)
20+
let session = client.startSession()
21+
22+
let db = client.db("test")
23+
let srcColl = db.collection("src")
24+
let destColl = db.collection("dest")
25+
let docToMove: Document = ["hello": "world"]
26+
27+
session.startTransaction().flatMap { _ in
28+
srcColl.deleteOne(docToMove, session: session)
29+
}.flatMap { _ in
30+
destColl.insertOne(docToMove, session: session)
31+
}.flatMap { _ in
32+
session.commitTransaction()
33+
}.whenFailure { error in
34+
session.abortTransaction()
35+
// handle error
36+
}
37+
```
38+
39+
### Transaction with Default Transaction Options
40+
41+
The default transaction options specified below apply to any transaction started on the session.
42+
43+
```swift
44+
let txnOpts = TransactionOptions(
45+
maxCommitTimeMS: 30,
46+
readConcern: ReadConcern(.local),
47+
readPreference: .primaryPreferred,
48+
writeConcern: try WriteConcern(w: .majority)
49+
)
50+
51+
let client = try MongoClient(using: elg)
52+
let session = client.startSession(options: ClientSessionOptions(defaultTransactionOptions: txnOpts))
53+
54+
session.startTransaction().flatMap { _ in
55+
// do something
56+
}.flatMap { _ in
57+
session.commitTransaction()
58+
}.whenFailure { error in
59+
session.abortTransaction()
60+
// handle error
61+
}
62+
```
63+
64+
### Transaction with Custom Transaction Options
65+
66+
**Note**:: Any transaction options provided directly to `startTransaction()` override the default transaction options for the session. More so, the default transaction options for the session override any options inherited from the client.
67+
68+
```swift
69+
let client = try MongoClient(using: elg)
70+
let session = client.startSession()
71+
72+
let txnOpts = TransactionOptions(
73+
maxCommitTimeMS: 30,
74+
readConcern: ReadConcern(.local),
75+
readPreference: .primaryPreferred,
76+
writeConcern: try WriteConcern(w: .majority)
77+
)
78+
79+
session.startTransaction(options: txnOpts).flatMap { _ in
80+
// do something
81+
}.flatMap { _ in
82+
session.commitTransaction()
83+
}.whenFailure { error in
84+
session.abortTransaction()
85+
// handle error
86+
}
87+
```
88+
89+
## See Also
90+
- [MongoDB Transactions documentation](https://docs.mongodb.com/manual/core/transactions/)

0 commit comments

Comments
 (0)