Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Decodable to get the object and document ID with Firestore

I have a simple User class which has the following fields:

{ 
  "localIdentifier": "xyc9870",
  "isOnline": false,
  "username": "ZS"
}

I want to use Swift's Decodable to easily turn the QueryDocumentSnapshot into a type safe Swift struct. I also want to make sure that I get the documentID from the QueryDocumentSnapshot for updating the object later.

This is what I'm currently using to decode but obviously it misses the documentId

struct User: Decodable {

    let localIdentifier: String
    let username: String
    let isOnline: Bool

}

Would love a hand here. Thanks!

like image 983
Zack Shapiro Avatar asked Nov 16 '18 15:11

Zack Shapiro


People also ask

How do I find firestore ID of documents?

How do I get data from firestore using ID? getFirestore() → Firestore Database. doc() → It takes references of database, collection name and ID of a document as arguments. getDoc() → getDoc() query gets data of a specific document from collection based on references mentioned in the doc() method.

How do I get a random document ID in firestore?

An easy way to grab random documents is get all the posts keys into an array ( docA , docB , docC , docD ) then shuffle the array and grab the first three entries, so then the shuffle might return something like docB , docD , docA .

Can two documents have the same ID in firestore?

You cannot have several documents with the same ID in one Collection: a document ID must be unique across a collection.


1 Answers

I wrote myself a small convenience extension that just brings the documentID into the data JSON and then I can use the simple struct below

extension QueryDocumentSnapshot {

    func prepareForDecoding() -> [String: Any] {
        var data = self.data()
        data["documentId"] = self.documentID

        return data
    }

}

Decode using:

struct User: Decodable {

    let documentId: String
    let localIdentifier: String
    let username: String
    let isOnline: Bool

}

if let user = try? JSONDecoder().decode(User.self, fromJSONObject: doc.prepareForDecoding()) {
    ...
}

Edit:

My JSONDecoder extension

extension JSONDecoder {
    func decode<T>(_ type: T.Type, fromJSONObject object: Any) throws -> T where T: Decodable {
        return try decode(T.self, from: try JSONSerialization.data(withJSONObject: object, options: []))
    }
}
like image 114
Zack Shapiro Avatar answered Nov 10 '22 16:11

Zack Shapiro