Reputation: 4643
There are the following domain structs, that represents Firebase documents. For this case, the payment document is not under (and does not belong) account document. It does not make sense to make ScheduledPayment as a sub collection of an Account.
import Foundation
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
struct Account: Codable, Identifiable {
@DocumentID
var id: String?
}
struct ScheduledPayment: Codable, Identifiable {
@DocumentID
var id: String?
var account: Account
var trigger: Timestamp
}
The account
field needs to be of "reference" Firebase type. It cannot be a simple string. Here is the picture showing how it is defined in Firestore UI.
I was able to do this in NodeJS (and it creates reference type as expected):
await db
.collection("nextScheduledPayment")
.add({
account: db.doc(`accounts/${accountRef.id}`),
trigger: Timestamp.now()
}
);
How to define a reference type in Swift struct? I tried these two approaches, but both of them throw Terminating app due to uncaught exception 'FIRInvalidArgumentException', reason: 'Unsupported type: __SwiftValue' terminating with uncaught exception of type NSException
exception.
This one is the closest implementation to what works in NodeJS (JavaScript), but it throws an exception mentioned above.
import Foundation
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
struct ScheduledPayment: Codable, Identifiable {
@DocumentID
var id: String?
var account: DocumentReference
var trigger: Timestamp
}
let ref = db.document("accounts/\(id)")
let payment = ScheduledPayment(account: ref, trigger: trigger)
let _ = try db
.collection("nextScheduledPayment")
.addDocument(from: payment)
This might make sense, if there would be some @Reference annotation or something like that, but I was not able to find it in the documentation nor in the code of Firestore library.
import Foundation
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
struct ScheduledPayment: Codable, Identifiable {
@DocumentID
var id: String?
var account: Account
var trigger: Timestamp
}
let account = Account()
let payment = ScheduledPayment(account: account, trigger: trigger)
let _ = try db
.collection("scheduledPayment")
.addDocument(from: payment)
Upvotes: 3
Views: 1032
Reputation: 4643
The solution to persist a document reference is the following (the option #1 that was mentioned in the question):
import Foundation
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
struct ScheduledPayment: Codable, Identifiable {
@DocumentID
var id: String?
var account: DocumentReference
var trigger: Timestamp
}
let ref = db.document("accounts/\(id)")
let payment = ScheduledPayment(account: ref, trigger: trigger)
let _ = try db
.collection("nextScheduledPayment")
.addDocument(from: payment)
My error was caused by including an object in the whereField
filter:
let account: Account = // the way you get the object
db.collection("scheduledPayment")
.whereField("account", isEqualTo: account)
The correct way to filter is the following:
let account: Account = // the way you get the object
db.collection("scheduledPayment")
.whereField("account", isEqualTo: db.document("accounts/\(id)"))
...hope it helps to someone...
Upvotes: 1
Reputation: 12385
DocumentReference
has a property named path
which is a String
representation of the document reference. Therefore, you can use this property in your Codable
structure. For convenience, you can include a computed property in the structure that returns a DocumentReference
using this path. The computed property won't interfere with the Codable
protocol.
struct Payment: Codable {
let docRefPath: String
var docRef: DocumentReference {
return Firestore.firestore().document(docRefPath)
}
}
Usage is straightforward.
// set
Firestore.firestore().document("someCollection/someDocument").getDocument { (snapshot, error) in
if let doc = snapshot,
let docRef = doc.get("docRef") as? DocumentReference {
let payment = Payment(docRefPath: docRef.path)
}
}
// get
payment.docRef.getDocument { (snapshot, error) in
// ...
}
Upvotes: 2