【问题标题】:How to map a Firestore DocumentID to a RealmObject attribute?如何将 Firestore DocumentID 映射到 RealmObject 属性?
【发布时间】:2021-03-05 05:24:32
【问题描述】:

我正在尝试使用 Firestore 在云中提供一些数据,这些数据可以下载并存储在 iOS 设备上的 Realm 数据库中。 我要存储的对象的结构是:

import Foundation
import RealmSwift
import FirebaseFirestore
import FirebaseFirestoreSwift

@objcMembers class Flashcard: Object, Codable{

@objc dynamic var id: String? = NSUUID().uuidString 
@objc dynamic var character: String?
@objc dynamic var title: String?
@objc dynamic var translation: String?
@objc dynamic var created: Date = Date()
let deck = LinkingObjects<FlashcardDeck>(fromType: FlashcardDeck.self, property: "cards")

override class func primaryKey() -> String? {
    return "id"
}

private enum CodingKeys: String, CodingKey {
    case id
    case character
    case translation
    case created
    case title
}

如果我尝试将 documentID 映射到我的 id 属性

@DocumentID @objc dynamic var id: String? = NSUUID().uuidString 

如果出现以下错误:

'Primary key property 'id' does not exist on object 'Flashcard'

我该如何解决这个问题?

编辑:为了更容易理解,这里是我的 Firestore 数据库的屏幕截图:

“PredifinedDecks”集合将存储许多套牌。例如id = DF59B1B3-BD22-47CE-81A6-04E7A274B98F 代表一副牌。每个牌组将存储一个数组/列表,其中包含卡片。

【问题讨论】:

  • 编码键枚举中省略了 id。此外,@DocumentID 不是可选的 - 一般而言,如果您将 JSON 导入可编码对象,则 documentId 将像这样填充:@DocumentID var docId: String!。话虽如此,Firebase 快照文档可以通过其字段值访问,当您可以直接访问字段时,为什么要跳过可编码的箍呢? self.a = doc.get("a") as? String ?? "default value"
  • 哦,是的,你是对的。我忘记了编码键中的 id。但这只是一个错字,它已经在我的代码中了。当我只有一个文档时,我觉得您通过字段值访问文档的建议很有帮助,但在我的情况下,我有两个其他不同的类/对象类型要存储在 firestore 中。你能不能给我一个更详细的例子?
  • 文档的数量不会对您的对象结构产生影响——一般来说,集合中的每个文档都映射到代码中的一个文档。您是说将不同的数据作为单独的文档存储在同一个集合中?
  • 不,我的结构看起来像: DECK 1: List(card1, card2,...) / DECK2: List(card3, card4,...) 其中 Deck 和 Card 是不同类型的对象.
  • 这不是很清楚,因为我们不知道它在您的结构中是如何布置的。也许您可以在问题中包含您的 Firebase 结构的屏幕截图,以使其更加清晰。

标签: swift firebase google-cloud-firestore realm


【解决方案1】:

不确定我是否完全理解这个问题,但让我从高层次上解决这个问题。

似乎有一个包含文档的 PredefinedDecks(一个集合)。每个文档都有一个卡片字段(一个数组)和一些其他字段数据。如果目标是读取所有文档(卡片组)及其子数据并将它们存储为领域对象,那么这是一种解决方案。从一个 Realm 对象开始,以保​​存来自 Firestore 的数据

class DeckClass: Object {
    @objc dynamic var deck_id = ""
    @objc dynamic var created = ""
    @objc dynamic var title = ""
    let cardList = List<CardClass>()

    convenience init(withDoc: QueryDocumentSnapshot) {
        self.init()
        self.deck_id = withDoc.documentID
        self.title = withDoc.get("title") as? String ?? "no title"
        self.created = withDoc.get("created") as? String ?? "no date"
        let cardArray = withDoc.get("cards") as? [String]
        for card in cardArray {
            let card = CardClass(withCard: card) {
                self.cardList.append(card)
            }
        }
    }
}

这样,您只需从 Firestore 为每个文档传递 documentSnapshot,该类就会相应地填充其属性。

以及读取 Firestore 的代码

func readDecks() {
    let decksCollection = self.db.collection("PredefinedDecks")
    decksCollection.getDocuments(completion: { documentSnapshot, error in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        for doc in documentSnapshot!.documents {
            let deck = DeckClass(withDoc: doc)
            self.decksList.append(deck) //a Realm List class object? Something else?
        }
    })
}

【讨论】:

  • 谢谢!这似乎是我的用例的解决方案。在 Firestore 数据库中存储 RealmObject 的最有效方法是什么?
  • @kirkyoyx 如果没有更多上下文,这真的很难说。换句话说,技术上您可以对领域对象进行编码并将该对象存储在 Firestore 中(例如作为字符串)。但我不认为那是你想要的。此外,Realm 去年在提供的产品方面取得了巨大的飞跃,该产品在某些方面可以做 Firestore 所做的事情——从而有可能完全消除 Firestore,简化项目。因此,我们需要了解这样做的目的、您想要获取哪些数据、为什么使用 Firestore 等。可能最适合单独的问题。
猜你喜欢
  • 2020-09-14
  • 1970-01-01
  • 2018-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多