【问题标题】:How to query Firebase for keys that match a string prefix如何在 Firebase 中查询与字符串前缀匹配的键
【发布时间】:2013-06-26 19:40:59
【问题描述】:

由于 firebase 不支持任何空间索引,所以我使用 geohash,有人在这里建议。 Geohash 正在使用字符来查找附近。

假设我在 firebase 中有 w22qt4vhye1c w99qt4vdf4vc w22qt4vhzerct geohash 存储,我只想查询接近 w22qt4 的 geohash。

怎么做?

我知道 firebase 有 startAt。我试过了,还是不行。

更新

将 geohash 存储到 firebase

//Encode lat lng, result w22qt4vhye1c3
var geoHashLatLng = encodeGeoHash(lat,lng);
firebaseRef.child('/geohash/' + geoHashLatLng).set(id); 

所以在 json 中

  root
   - geohash
      - w22qt4vhye1c3
         - id
      - z99qt4vdf4vc
      - w22qt4vhzerct

我的问题在这里。 我只想查询从字符w22qt4 开始的geohash。我们可以在 firebase 中做到这一点吗?

更新 2 startAt() 似乎不是以...开头的字符查询

示例:我有以下 gehash

geohash 节点

geohash
  - a123
  - a333
  - b123
  - c123
  - d123

使用以下代码

var firebaseRef = new Firebase('https://test.firebaseio.com');
var query = firebaseRef.child('/geohash').startAt(null, 'a');
query.on('child_added', function(snapshot) {
    console.log(snapshot.name());
});

会得到这个结果

startAt(null, 'a') //return a123, a333, b123, c123, d123
startAt(null, 'c123') //return c123, d123
startAt(null, 'd') //return d123

我的预期结果

startAt(null, 'a') //return a123, a333
startAt(null, 'c123') //return c123
startAt(null, 'd') //return d123

我的猜测,startAt() 将按顺序查询 26 个字母但不匹配。 那么,我可以在 firebase 中做什么,以便获得上述预期结果?

【问题讨论】:

  • 您能否提供您正在尝试的代码 sn-p,以便我提供更有意义的反馈?
  • @AndrewLee 嗨,我刚刚更新了我的问题,请看一下。
  • 您可以使用“endAt”在特定键处结束。请参阅下面对我的帖子的修改。

标签: firebase


【解决方案1】:

除了上面 Andrew 的回答之外,您想要做什么才能使用 geohashes 获得所需的效果(即能够进行前缀查询,让您在“查询”中指定准确性,具体来说,例如每 3 个字符在geohash 为您提供 ~ +-80km) 是以更细化和离散化的方式存储数据。

因此,与其现在如何存储数据,不如通过将 geohash 字符串键切割成片段来保存数据(我已经在 3 个字符边界处完成了,但您应该选择适当的标记化为您提供所需准确性的策略)并将每个片段用作子名称,如下所示:

root
  - geohash
      - w22
        - qt4
          - vhy
            - e1c
              - w22qt4vhye1c3
                - id
          - vhz
            - erc
              - w22qt4vhzerct
                - id
      - z99
          - qt4
            - vdf
              - z99qt4vdf4vc
                - id

然后,就像您的问题一样,当您需要获取所有以 w22qt4 开头的地理哈希时,您将针对:

firebaseRef.child('/geohash/w22/qt4/')

这会给你vhyvhz 孩子,然后他们有你感兴趣的所有实际geohashes。

【讨论】:

  • 如何查询子子项下的val在哪里?我阅读了 Firebase 文档。我找到了hasChildren()forEach()。那是正确的使用方法吗?顺便说一句,我可以在 angularFire 中使用吗?因为我正在使用带有 angularjs 的 firebase。
  • 由于数据已按给定方式非规范化,因此您无需应用 Firebase 查询。您可以将侦听器附加到树中的适当级别,它将返回正在返回的快照中的所有子子级。
【解决方案2】:

您可以使用普通的 startAt 查询来查找指定键附近的键。例如,在这种情况下,您会:

var query = firebaseRef.child("geohash").startAt(null, 'c').limit(5);
query.on("child_added", ...);

当按字典顺序排序时,这将为您提供 geoHashLatLng 之后的 5 个元素。

如果您想在某个指定的键处结束查询,您也可以这样做。例如:

var query = firebaseRef.child("geohash").startAt(null, 'c').endAt('d');

【讨论】:

  • 这没有得到我想要的,我再次更新了我的问题。这次我想的更清楚了。请检查一下。谢谢
  • 对不起,我忘了说我不知道​​结局是什么。我加了一个小提琴。请看plnkr.co/edit/Wtkq4978r1a4dnSLl9qi?p=preview
  • 我们没有办法只通过前缀查询。您需要弄清楚查询应该在哪里结束。我们按字典顺序排序,所以如果你想要 c*,那么你可以 startAt c 和 endAt d,然后丢弃任何与 d 完全匹配的东西。
  • 正如@AndrewLee 所提到的,Firebase 中没有精确的 {...}.prefix() 查询,但是您可以在使用 geohashes 时完成同样的事情,您知道它只包含字母数字字符,通过在结束查询中组合 startAt()endAt() 和非字母数字字符。例如,要搜索前缀abcd,您可以使用{...}.startAt(null, 'abcd').endAt(null, 'abcd~'),它将捕获所有以abcd 开头的地理哈希,并且不需要在客户端进行过滤。显然,在 abcd~ 之后按字典顺序排序的任何键都会丢失,但这不会影响 geohashes。
  • 感谢@RobDiMarco 的工作。如果它存在于Docs 中,您能否显示在哪里阅读此内容
猜你喜欢
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 2022-06-10
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
相关资源
最近更新 更多