【问题标题】:How to structure a search list in Firestore?如何在 Firestore 中构建搜索列表?
【发布时间】:2019-01-05 03:25:18
【问题描述】:

我想在我的应用中显示一个艺术家列表,用户可以通过这些列表进行搜索。但是我不确定如何将其保存在 Firestore 中?

首先,我为每个 DJ 创建了一个包含一个文档的集合“searchLists”,但这意味着要读取大量文档,因此这是不可能的。

现在我创建了一个名为“artists”的文档,其中包含一个包含所有艺术家的字段“artistsDictionary”。

| searchLists (collection)
   * artists (document)
      - artistsArray (array)
          0: (map)
            name: "Artist 0" (string)
          1: (map)
            name: "Artist 1" (string)
          2: (map)
            name: "Artist 2" (string)

然后我检索并解析数组如下:

let docRef = db.collection("searchLists").document("artists")
docRef.getDocument { (document, error) in
    if let document = document, document.exists {
        guard let documentData = document.data() else { return }
        let artistsDictionaryArray = documentData["artistsArray"] as? [[String: Any]] ?? []
        let parsedArtists = artistsDictionaryArray.compactMap {
            return SimpleArtist(dictionary: $0)
        }
        self.artistsArray = parsedArtists
    } else {
        print("Document does not exist")
    }
}

(SimpleArtist 是一个包含“名称”字段的结构。)

我的意思是,它有效,但我还是 Firestore 的新手,这似乎有点不对劲。是吗?还是我应该/可以这样做?

【问题讨论】:

    标签: ios swift firebase google-cloud-firestore


    【解决方案1】:

    首先,我为每个 DJ 创建了一个包含一个文档的集合“searchLists”,但这意味着要读取大量文档,所以这是不可能的。

    这是正确的方法,所以你应该继续它。

    我为什么这么说?

    根据 Cloud Firestore 数据库中有关 modeling data 的官方文档:

    Cloud Firestore 针对存储大量小文档进行了优化。

    将数据存储在数组中并不是一个坏选择,但这很可能会被使用,比如存储favorite djs。我这么说是因为文件在 Firestore 中有限制。因此,在您可以将多少数据放入文档时存在一些限制。根据usage and limits的官方文档:

    文档的最大大小:1 MiB(1,048,576 字节)

    如您所见,单个文档中的数据总量限制为 1 MiB。当我们谈论存储文本时,您可以存储几乎所有内容,但随着您的数组变得越来越大,请注意这个限制。

    【讨论】:

    • 我明白了,谢谢!最终我会在集合中添加一个监听器,这样如果添加了一个文档,我就不必再次获取整个集合,它只会读取 1 个额外的文档而不是全部?
    • 有没有办法在用户重新启动应用程序后也不再获取整个集合?我可以将所有文档保存在一个数组中,但监听器当然会消失,我是否愿意收听所有文档,除了那些我保存并更新的文档?或者我是否至少需要在应用启动时收听收藏?
    • 对于 Android 和 iOS,offline persistence 默认启用。所以这意味着如果数据库中没有任何变化,您可以直接从缓存中获取数据。 “我可以听听除了我保存和更新的文件之外的所有文件吗?”这就是 Firestore 的工作原理。如果只获取新数据而再次获取整个集合。
    【解决方案2】:

    首先,Alexs 的回答是 100% 正确的。

    我想添加一些额外的数据点,从长远来看可能会对您有所帮助。

    第一项是数组。数组在 NoSQL 数据库中非常具有挑战性——虽然它们通过索引 0、1、2 提供逻辑序列数据,但它们的行为不像代码中的数组——例如;假设您想在索引处插入一个项目。好吧 - 你不能(*你可以,但它不仅仅是一个简单的“插入”调用)。此外,您不能在查询中定位数组元素,这会限制它们的用处。 Firestore 数组字段中最小的更改单位是整个字段 - 无法对字段的单个元素进行较小的更改。解决方法是不使用数组并让 FireStore 为您的数据“对象”即时创建 documentID,例如节点的“键”

    第二个问题 - (目前可能不是问题)是如何处理数据。假设您发布了您的应用程序,并且用户的收藏中有 200 万艺术家 - 使用您的代码,一次下载所有数据,这可能不是最好的 UI 体验,但另外,它可能会压倒设备。因此,在设备和用户上处理“块”数据会容易得多。

    所以我整理了一些示例代码来帮助解决这个问题。

    首先是一个用于存储艺术家数据的类。只需跟踪 documentID 和艺术家姓名即可。

    class ArtistClass {
        var docId = ""
        var name = ""
    
        init(aDocId: String, aName: String) {
            self.docId = aDocId
            self.name = aName
        }
    }
    

    还有一个类数组来保留艺术家。这将是 tableView 的潜在数据源

    var artistArray = [ArtistClass]()
    

    这是将艺术家写为文档而不是数组。 documentID 是 FireStore 生成的为每位艺术家创建的“密钥”。

    func writeArtists() {
        let artistsRef = self.db.collection("artists")
    
        let floyd = [
            "name": "Pink Floyd"
        ]
        let zep = [
            "name": "Led Zeppelin"
        ]
        let who = [
            "name": "The Who"
        ]
    
        artistsRef.addDocument(data: floyd)
        artistsRef.addDocument(data: zep)
        artistsRef.addDocument(data: who)
    }
    

    然后函数读取所有个艺术家。

    func readArtists() {
        let artistsRef = self.db.collection("artists")
    
        artistsRef.getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in querySnapshot!.documents {
                    let docId = document.documentID
                    let name = document.get("name") as! String
                    let artist = ArtistClass(aDocId: docId, aName: name)
                    self.artistArray.append(artist)
                }
    
                for a in self.artistArray { //prints the artists to console
                    print(a.docId, a.name)
                }
            }
        }
    }
    

    所以您在 Firestore 中的数据如下所示

    artists (collection)
       8lok0a0ksodPSSKS
          name: "Let Zeppelin"
       WKkookokopkdokas
          name: "The Who"
       uh99jkjekkkokoks
          name: "Pink Floyd"
    

    那么很酷的部分。假设您有一个 tableView,它一次显示 10 个艺术家,并带有向下按钮以查看下一个 10。进行此更改

    let artistsRef = self.db.collection("artists").order(by: "name").limit(to: 10)
    

    哦 - 你会注意到排序功能现在转到服务器而不是设备 - 所以如果有一百万个艺术家,它会在传送到设备之前在服务器上进行排序,这将大大加快速度。

    您还可以更轻松地对特定艺术家数据执行查询,并且您无需担心存储问题,因为每个艺术家都是他们自己的文档,而不是所有艺术家合而为一。

    希望有帮助!

    【讨论】:

    • 太棒了,谢谢!这当然有助于理解它。所以我在偏离轨道之前就在正确的轨道上。我会在发布问题后进行谷歌搜索,但我想我也可以问你:例如,获取限制为 10 的文档是否足够快以处理表格视图中的滚动?
    • @Bram-N 是的,它已经足够快了——事实上,有很多关于这样做的信息。它被称为无限滚动分页。这里有很多关于 SO 的不同方法的数据。
    猜你喜欢
    • 1970-01-01
    • 2020-05-04
    • 2019-09-07
    • 2011-11-22
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    相关资源
    最近更新 更多