在 Firestore 中查询 Geohashes

Querying Geohashes in Firestore

最近我一直在研究 Geohashes 和 Firestore。 我的待办事项场景是收集文件(餐厅),每个餐厅都会有 Geohashes 列表,这些列表会交付给。

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

最初的想法是将所有 geohashes 放在餐厅文档的子集合中,但我发现无法在文档的子集合中执行查询。

第二个想法是将 geohashes 提取到交付区域集合中的顶级。

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

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

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

I want to avoid adding the geoashes in the document restaurant as the document can be many times bigger than it should be.

是的,不要那样做,因为文件有限制。因此,对于可以放入文档的数据量存在一些限制。根据有关 usage and limits 的官方文档:

Maximum size for a document: 1 MiB (1,048,576 bytes)

如您所见,单个文档中的数据总量不得超过 1 MiB。当我们谈论存储文本时,您可以存储很多,但如果您使用的是复杂对象,这不是一个选项。

The initial idea is to have all of the geohashes in a subcollection of the restaurant document but I found out its not possible to perform queries in subcollection of documents.

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

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

因此,可以让您获取特定餐厅的所有 geohash 对象的查询将完美无缺。

The second idea was to extract the geohashes to top level in a collection of delivery areas

不是一个糟糕的解决方案,但您应该创建一个额外的 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。

复制数据时,需要牢记一件事。以与添加数据相同的方式,您需要维护它。换句话说,如果你想 update/detele 一个项目,你需要在它存在的每个地方都这样做。

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 可能值得一试。