【问题标题】:Querying Geohashes in Firestore在 Firestore 中查询 Geohashes
【发布时间】:2019-03-17 13:59:22
【问题描述】:

最近我一直在玩 Geohashes 和 Firestore。 我的待办事项场景是有一组文件(餐馆),每家餐馆都有送货到的 Geohashes 列表。

我想避免在文档餐厅中添加 geoashes,因为文档可能比应有的大很多倍。

最初的想法是将所有地理哈希都放在餐厅文档的子集合中,但我发现它不可能在文档的子集合中执行查询。

第二个想法是将地理哈希提取到交付区域集合中的顶层。

document:{ restaurantName: "aRestaurant", 
deliveryArea: Arraylist<String> }

这种情况下的问题是,我将返回一个餐厅名称列表,然后我需要在其中查询餐厅集合以获取它们,据我所知,我无法在查询中执行 OR 操作。

这是我第一次使用文档数据库和 Firestore。任何指导将不胜感激。

【问题讨论】:

    标签: firebase google-cloud-firestore geohashing geofirestore


    【解决方案1】:

    我想避免在文档餐厅中添加 geoashes,因为文档可能比应有的大很多倍。

    是的,不要这样做,因为文档有限制。因此,在您可以将多少数据放入文档时存在一些限制。根据usage and limits的官方文档:

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

    如您所见,单个文档中的数据总量限制为 1 MiB。当我们谈论存储文本时,您可以存储几乎所有内容,但如果您使用复杂的对象,这不是一个选项。

    最初的想法是将所有地理哈希都放在餐厅文档的子集合中,但我发现它不可能在文档的子集合中执行查询。

    这是一个很好的解决方案。您的数据库结构应如下所示:

    Firestore-root
       |
       --- restaurants (collection)
            |
            --- restaurantId (document)
                    |
                    --- geohashes (collection)
                          |
                          --- geohashId (document)
                                |
                                --- //details about the location
    

    因此,可以让您获取特定餐厅的所有 geohash 对象的查询将非常有效。

    第二个想法是将地理哈希提取到交付区域集合中的顶层

    这不是一个糟糕的解决方案,但您应该创建一个额外的get() 调用,以获取餐厅详细信息,但即使这样做,也不是一个糟糕的调用,Firestore 中的嵌套查询没有问题。不需要OR操作。

    编辑:根据您的评论,是的,您是对的,您无法查询数据库以取回餐厅对象,但我们也有一个解决方法。在这种情况下,您应该考虑通过添加这样的新集合来扩充您的数据结构以允许反向查找:

    Firestore-root
       |
       --- geohashes (collection)
             |
             --- geohashId (document)
                   |
                   --- geohashRestaurants (collection)
                            |
                            --- restaurantId
                                   |
                                   --- //restaurant details
    

    这种技术称为denormalization,如您所见,这意味着复制数据。但是您需要知道,对于 Firebase,复制数据没有问题。这是一种很常见的做法,为此,我建议您观看此视频,Denormalization is normal with the Firebase Database。适用于 Firebase 实时数据库,但同样的原则也适用于 Cloud Firestore。

    当您复制数据时,需要牢记一件事。与添加数据的方式相同,您需要对其进行维护。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都这样做。

    【讨论】:

    • 感谢 Alex 的确认。现在最大的问题是,如果我遵循这些想法中的任何一个,我就无法查询 geohashes(集合)以返回餐厅(文档)。 ` db.collection(restaurants).get().where(geohash == ABCD123)` 上面的查询是我所追求的,不幸的是,在firestore中查询子集合不可用。 :(
    【解决方案2】:

    firebaser 在这里

    我们用于 Firebase 实时数据库的原始 GeoFire 库通过为 geohashes 设置一个单独的顶级节点准确地解决了这个问题。该节点下的每个键通常对应于另一个顶级节点中的实际实体的键。

    比如:

    locations
      key1: { g: "sa7ads", l: [ 14.5232, -156.17843 ] },
      key2: { g: "fds347", l: [ -127.172, 167.1324 ] }
    restaurants
      key1: { name: "This is the first restaurant", ... },
      key2: { name: "This is the second restaurant", ... },
    

    使用此结构,您对/locations 执行地理查询,然后读取/restaurants/$key 范围内每个餐厅的附加信息。这可以很好地扩展。

    我建议对 Cloud Firestore 采用相同的方法。您将拥有两个顶级集合:一个包含(较小的)位置数据,另一个包含有关每家餐厅的(较大的)附加数据。尽管您最终会阅读更多文档,但这会减少您阅读的数据量。您必须平衡这两者(带宽与文档读取)。

    几个月前,我提供了一个talk about performing geoqueries on Cloud Firestore,可能值得一试。

    【讨论】:

    • 嗨弗兰克,你的演讲太棒了!我确实看过 GeoFire 库,看起来非常好。虽然是在观看您的演讲时提出的问题之一,但如果其中一家餐厅想要改变送货地点,会发生什么?您将需要获取包含它的所有文档(geohashes),更改它们并保存它们。对于无服务器基础架构而言,这听起来像是一项大型操作:/(我想云功能在这种情况下可能会派上用场)
    猜你喜欢
    • 1970-01-01
    • 2018-04-11
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    相关资源
    最近更新 更多