使用 Geofire + Firebase 过滤结果

Posted

技术标签:

【中文标题】使用 Geofire + Firebase 过滤结果【英文标题】:Filtering results with Geofire + Firebase 【发布时间】:2015-12-18 02:18:21 【问题描述】:

我正在尝试弄清楚如何使用 Geofire 进行过滤器查询。 假设我有不同类别的餐厅。我想将该类别添加到我的查询中。我该怎么办?

我现在的一种方法是使用 Geofire 查询键,通过每个键运行 for 循环并获取餐厅,然后将适当的餐厅插入到数组中。 这些似乎效率很低。有没有其他方法可以解决这个问题?

理想情况下,我将获得过滤后的结果,并且仅在它们即将显示时加载每个项目。

干杯!

【问题讨论】:

Firebase 查询只能按一个条件过滤。 Geofire 已经做了一些“魔法”,让它能够过滤经度和纬度。向该等式添加另一个属性可能是可能的,但远远超出了 Geofire 默认处理的范围。见***.com/questions/34084347/…(我认为是重复的)。 好的,那么你将如何按其他条件过滤它? 这取决于:如果您甚至只想一次访问一个类别,您可以将餐厅放在每个类别的***节点中,并将 Geofire 指向一个类别。但更常见的是,您只需在客户端代码中进行额外的过滤。如果您担心它的性能:测量它,共享代码、JSON 数据和测量结果。 @FrankvanPuffelen 您如何将 Geofire 归为一类?您的意思是从 geofire 中查询键并检查每个键是否属于该类别? 不。只需为每个类别拥有单独的***键,您可以在其下拥有该类别中项目的地理数据。 IE。 /category1/items.../category2/items... 等。实际项目数据本身可以保存在单个全局/共享/items 【参考方案1】:

Firebase 查询只能按一个条件过滤。 Geofire 已经做了很多"magic" 以允许它同时过滤经度和纬度。向该等式添加另一个属性可能是可能的,但远远超出了 Geofire 默认处理的范围。见GeoFire: How to add extra conditions within the query?

如果您一次只想访问一个类别,您可以将餐厅放在每个类别的***节点中,并将 Geofire 指向一个类别。

/category1
    item1
        g: "pns0h0mf2u"
        l: [-53.435719, 140.808716]
    item2
        g: "u417k3dwub"
        l: [56.83069, 1.94822]
/category2
    item3
        g: "8m3rz3s480"
        l: [30.902225, -166.66809]
/items
    item1: ...
    item2: ...
    item3: ...

在上面的示例中,我们有两个类别:category1 有 2 个项目,category2 只有 1 个项目。对于每个项目,我们都会看到 Geofire 使用的数据:geohash 以及经度和纬度。我们还保留了一个包含这 3 个项目的其他属性的列表。

但更常见的是,您只需在客户端代码中进行额外的过滤。如果您担心它的性能:测量它,共享代码、JSON 数据和测量结果。

【讨论】:

我明白了。似乎通过客户端过滤它不那么复杂。谢谢! 由于 geohash 上的索引,是否将 lat/lon 与 geohash 一起存储会影响性能?【参考方案2】:

这是一个老问题,但我在网上的一些地方看到过,所以我想我可以分享一个我用过的技巧。

问题

如果您的数据库中有一个大型集合,例如可能包含数十万个键,那么将它们全部获取可能是不可行的。如果您尝试根据位置和其他条件过滤结果,您会遇到以下问题:

    执行位置查询 循环遍历每个返回的geofire key,并抓取数据库中的对应数据 检查每条返回的数据,看看它是否符合其他条件

不幸的是,这是很多网络请求,速度很慢。

更具体地说,假设我们希望让所有用户都在其中,例如100 英里的特定位置,男性年龄在 20 到 25 岁之间。如果 100 英里内有 10,000 名用户,这意味着需要 10,000 个网络请求来获取用户数据并比较他们的性别和年龄。

解决方法:

您可以将比较所需的数据存储在 geofire 键本身中,并用分隔符分隔。然后,您只需拆分 geofire 查询返回的键即可访问数据。您仍然需要过滤它们,但它比发送数百或数千个请求要快得多。

例如,您可以使用以下格式:

UserID*gender*age,可能类似于facebook:1234567*male*24。重点是

    用分隔符分隔数据点 使用有效字符作为分隔符 -- “它可以包含除 .$ # [ ] / 和 ASCII 控制字符 0-31 和 127 之外的任何 unicode 字符。)” 使用在您的数据库中其他地方找不到的字符 - 我使用了 *,但这可能不适合您。不要使用来自-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz 的任何字符,因为这些字符对于firebase 的push() 生成的密钥是公平的 为数据选择一致的顺序 - 在本例中,首先是 UserID,然后是性别,然后是年龄。

您最多可以在 Firebase 密钥中存储 768 bytes of data,这有很长的路要走。

希望这会有所帮助!

【讨论】:

Firebase 使用 websockets,这消除了对这种解决方法的需要,是吗?问题不在于您发出多少请求,因为您只发出一个来创建套接字和一个关闭。问题在于过滤数据,正如您所说,当数据集包含成千上万个条目时,这可能很重。我认为,最好的方法是以一种更好地对节点进行索引和对子节点进行排序的方式来构建数据 @jhm 你能详细说明如何做到这一点吗?我对 ZenPylon 方法的问题是,即使地球另一端的人更新了分支,每次发生变化时你都必须运行过滤器。这非常不理想,所以我想知道最好的方法是什么。

以上是关于使用 Geofire + Firebase 过滤结果的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Firebase 中使用 geoFire 存储 CLLocation 对象

如何让用户在我在 geofire、Firebase 的位置附近

我想使用 GeoFire 在 android 中填充 Firebase Recycler View

如何在没有 Geofire 的情况下将位置对象保存在 Firebase 中?

写入 Firebase 时 Geofire 崩溃

使用 CocoaPods 添加 GeoFire 依赖项