简体   繁体   中英

How can I get the document ID when using Codable in Firestore?

I want to get document id to work with it for editing and deleting document after decoding. How can I do this?

My model:

struct MoodRecord: Codable, Hashable, Identifiable {
   @DocumentID var id: String?
   let user: String
   let date: String
   let time: String
   let mood: Int
}

My function:

class func getRecords <T: Decodable> (
    reference: CollectionReference,
    type: T.Type,
    completion: @escaping (Result<[T], Error>) -> Void
) {
    reference.whereField("user", isEqualTo: AuthManager.shared.getUserId() ?? "")
        .getDocuments { snapshot, error in
        if let documents = snapshot?.documents {
            do {
                let records: [T] = try documents.map { try $0.decoded(type: T.self) }
                completion(.success(records))
            } catch let error {
                completion(.failure(error))
            }
        } else if let error = error {
            completion(.failure(error))
        }
    }
}

My decoder:

extension QuerySnapshot {

    func decoded <T: Decodable> (type: T.Type) throws -> [T] {
        let objects: [T] = try documents.map { try $0.decoded(type: T.self) }
        return objects
    }
}

extension QueryDocumentSnapshot {

    func decoded <T: Decodable> (type: T.Type) throws -> T {
        let jsonData = try JSONSerialization.data(withJSONObject: data(), options: [])
        let object = try JSONDecoder().decode(type.self, from: jsonData)
        return object
    }
}

I use only auto-ID in Firestore and want to work with them in this task. Can I do this?

You can use Firestore's Codable support to map document IDs. No need to implement a custom decoder - we've done all the hard work for you.

Here is how.

1. Create a model for your data

You already did this. Looking at the attributes in your MoodRecord struct, I assume you want to use date and time to track timestamps, and mood to capture the value of an enum. I've updated the struct accordingly:

struct MoodRecord: Codable, Hashable, Identifiable {
  @DocumentID var id: String?
  var user: String
  var date: Date
  var time: Date
  var mood: Mood
}

enum Mood: String, Codable {
  case great
  case ok
  case good
  case bad
  case terrible
}

2. Map data using Codable

Fetching Firestore documents and mapping them to Swift structs becomes a one-liner thanks to Codable:

docRef.getDocument(as: MoodRecord.self) { result in
  // handle result
}

Here is a complete code snippet for fetching a single document:

private func fetchMoodRecord(documentId: String) {
  let docRef = db.collection("moodrecords").document(documentId)
  
  docRef.getDocument(as: MoodRecord.self) { result in
    switch result {
    case .success(let moodRecord):
      // A MoodRecord value was successfully initialized from the DocumentSnapshot.
      self.moodRecord = moodRecord
      self.errorMessage = nil
    case .failure(let error):
      // A MoodRecord value could not be initialized from the DocumentSnapshot.
      self.errorMessage = "Error decoding document: \(error.localizedDescription)"
    }
  }
}

3. Updating a document

To update a document using Codable, use the following code snippet:

func updateMoodRecord(moodRecord: MoodRecord) {
  if let id = moodRecord.id {
    let docRef = db.collection("moodRecords").document(id)
    do {
      try docRef.setData(from: moodRecord)
    }
    catch {
      print(error)
    }
  }
}

4.Adding new documents

Adding new documents is even easier:

func addMoodRecord(moodRecord: MoodRecord) {
  let collectionRef = db.collection("moodRecords")
  do {
    let newDocReference = try collectionRef.addDocument(from: moodRecord)
    print("Mood record stored with new document reference: \(newDocReference)")
  }
  catch {
    print(error)
  }
}

More

To learn more about how to map Firestore documents using Swift's Codable protocol, including how to map advanced data types such as date, time, colors, enums, how to fetch data using snapshot listeners, and how to handle any errors that might occur during the mapping process, check out Mapping Firestore Data in Swift - The Comprehensive Guide and the accompanying sample project on GitHub

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM