【问题标题】:Firebase - Query Indexed DataFirebase - 查询索引数据
【发布时间】:2021-05-22 23:52:32
【问题描述】:

我有以下 Firebase 数据用于谷歌地图上的标记:

'g' 是 lat('y') long('x') 数据的 Geohash。

规则如下:

    "markers": {
      // Schema validation
      "$key": {
        //Create Index on geohash
        ".indexOn":"g",
        // Key validation
        ".validate": "newData.hasChildren(['y', 'x'])",
        // Location coordinates validation
        "y" : {
            ".validate": "newData.isNumber() && newData.val() >= -90 && newData.val() <= 90"
        },
        "x" : {
            ".validate": "newData.isNumber() && newData.val() >= -180 && newData.val() <= 180"
        }
      },
    },

我想在数据库中找到所有具有 Geohash "dpt" 的标记。

我尝试了以下方法,但这不起作用,因为“键”不是“标记”子级的通配符。 如何形成查询以检查“标记”的每个子项的“g”,然后保存标识与查询匹配的标记的父按键。

var ref = firebase.database().ref().child('markers').child('key');
ref.orderByChild('g').startAt('9tb').on('value', function(snapshot) {
  var geoHash = snapshot.val();
  console.log("Geohash: ", geoHash);
});

这是文本 JSON 示例 Firebase 数据:

{
  "markers" : {
    "-KlRW2_rba1zBrDPpxSl" : {
      "g" : "9ru",
      "v" : true,
      "x" : -117.826127,
      "y" : 44.781139
    },
    "-KlTqMQyCcp14K_aMo9g" : {
      "g" : "9ru",
      "v" : true,
      "x" : -117.81246,
      "y" : 44.782722
    },
    "-Kldr6aLW-S2oGUdjAzI" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.028278,
      "y" : 48.041726
    },
    "-Kldw5z-D_cdrKnWCmp_" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.059073,
      "y" : 48.06427
    },
    "-Kle3Cx0QeqRy1h7aATN" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.146601,
      "y" : 48.084727
    },
    "-Kle7Fv1xkfb-7tr1P2L" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.183749,
      "y" : 48.095725
    },
    "-Kle7jffOcDuUzjAZg5F" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.18631,
      "y" : 48.096281
    },
    "-KleA4K1dojl1WtcWPSV" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.213735,
      "y" : 48.097471
    },
    "-KleABUDV4jcGpa8r6Ve" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.213725,
      "y" : 48.097485
    },
    "-KleKH81yer28MoVfEMW" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.325905,
      "y" : 48.106662
    },
    "-KleUD0juBdYZeoe_z-q" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.429659,
      "y" : 48.119794
    },
    "-Klo34L_G5agEOqpbovd" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.396003,
      "y" : 48.571614
    },
    "-Klo3R9kl7BA75jLv7Xh" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.396094,
      "y" : 48.571911
    },
    "-KltPx4gNnU0FW9BbRQL" : {
      "g" : "c0x",
      "v" : true,
      "x" : -123.961927,
      "y" : 49.149734
    },
    "-KltQHHSeS46eRZiEqJ5" : {
      "g" : "c0x",
      "v" : true,
      "x" : -123.962496,
      "y" : 49.149894
    },
    "-KltZAKh747Wp276lwtv" : {
      "g" : "c0x",
      "v" : true,
      "x" : -124.002884,
      "y" : 49.187565
    },
    "-KlyGT1ti-2h3Gvj9JTA" : {
      "g" : "c0z",
      "v" : true,
      "x" : -124.446747,
      "y" : 49.354767
    },
    "-KlyyQ707QUZgJo4raj0" : {
      "g" : "c0z",
      "v" : true,
      "x" : -124.868005,
      "y" : 49.548976
    },
    "-Klyz0xV1HM4CC1cRkc2" : {
      "g" : "c0z",
      "v" : true,
      "x" : -124.868662,
      "y" : 49.550011
    },
    "-KmDS0eTTxvcTRyDo6Ey" : {
      "g" : "c0z",
      "v" : true,
      "x" : -123.753916,
      "y" : 49.470945
    },
    "-KmJ5fZU7FGepOM-Dsd3" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.640735,
      "y" : 48.865098
    },
    "-KmTUx_PdegkTMa-U0_Q" : {
      "g" : "c28",
      "v" : true,
      "x" : -123.148974,
      "y" : 48.515291
    },
    "-KoNxTtS9tmuIi5WqSJ0" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.961665,
      "y" : 33.487971
    },
    "-KomZRSjPvEY32NccKjP" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.938777,
      "y" : 33.372255
    },
    "-KomZicmIkAugvZoYOFk" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.93924,
      "y" : 33.372432
    },
    "-Kom_Hkh69ay27Vcvd8g" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.937975,
      "y" : 33.372203
    },
    "-Kom__PTIp5XegcmBfg-" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.937818,
      "y" : 33.372542
    },
    "-Kom_x70rXZSp52uAO77" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.937855,
      "y" : 33.373511
    },
    "-KomaAzSPC3GBSgHxauG" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.938118,
      "y" : 33.373924
    },
    "-KomaRXxHhL6WhPlEYoY" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.938446,
      "y" : 33.374228
    },
    "-Komazt-91BrlsyXRBTa" : {
      "g" : "9tb",
      "v" : true,
      "x" : -111.937611,
      "y" : 33.372948
    },
    "-Koo6156pLEDnSX6W2is" : {
      "g" : "9xh",
      "v" : true,
      "x" : -105.768036,
      "y" : 39.773127
    },
    "-Koo6HaacQSYL9WUFHFk" : {
      "g" : "9xh",
      "v" : true,
      "x" : -105.608521,
      "y" : 39.683015
    },
    "-KosfSpl7Jnv0y2Yayue" : {
      "g" : "9xh",
      "v" : true,
      "x" : -106.109965,
      "y" : 40.074011
    },
    "-Kp6Wq6tc54oUKcIoVPY" : {
      "g" : "9w0",
      "v" : true,
      "x" : -111.503542,
      "y" : 35.064289
    },
    "-Kp6X0s4WpIGGxU31nDQ" : {
      "g" : "9w0",
      "v" : true,
      "x" : -111.584362,
      "y" : 35.111022
    },
    "-KpBpkjX2tYoaGbQIkVV" : {
      "g" : "9w0",
      "v" : true,
      "x" : -111.852989,
      "y" : 34.564051
    },
    "-KpBqBS10FM5LFT96yed" : {
      "g" : "9w0",
      "v" : true,
      "x" : -111.852024,
      "y" : 34.564459
    },
    "-KpBrZyra82zHA6jksmE" : {
      "g" : "9w0",
      "v" : true,
      "x" : -111.850959,
      "y" : 34.549598
    }
  }
}

规则:

    "markers": {
      //Create Index on geohash
      ".indexOn":"g",
      // Schema validation
      "$key": {
        // Key validation
        ".validate": "newData.hasChildren(['y', 'x'])",
        // Location coordinates validation
        "y" : {
            ".validate": "newData.isNumber() && newData.val() >= -90 && newData.val() <= 90"
        },
        "x" : {
            ".validate": "newData.isNumber() && newData.val() >= -180 && newData.val() <= 180"
        }
      },
    },

这里是 node.js 代码:

var firebase = require('firebase');
var config = firebase.initializeApp({
  apiKey: '',
  authDomain: '',
  databaseURL: '',
  projectId: '',
  storageBucket: '',
  messagingSenderId: ''
});
console.log('reading test database Geohash Data function');
var ref = firebase.database().ref().child('markers');
ref.orderByChild('g').startAt('9tb').on('value', function(snapshot) {
  var geoHash = snapshot.val();
  console.log("Geohash: ", geoHash);
});

这是输出:

reading test database Geohash Data function
Geohash:  {
  '-Kldr6aLW-S2oGUdjAzI': { g: 'c28', v: true, x: -123.028278, y: 48.041726 },
  '-Kldw5z-D_cdrKnWCmp_': { g: 'c28', v: true, x: -123.059073, y: 48.06427 },
  '-Kle3Cx0QeqRy1h7aATN': { g: 'c28', v: true, x: -123.146601, y: 48.084727 },
  '-Kle7Fv1xkfb-7tr1P2L': { g: 'c28', v: true, x: -123.183749, y: 48.095725 },
  '-Kle7jffOcDuUzjAZg5F': { g: 'c28', v: true, x: -123.18631, y: 48.096281 },
  '-KleA4K1dojl1WtcWPSV': { g: 'c28', v: true, x: -123.213735, y: 48.097471 },
  '-KleABUDV4jcGpa8r6Ve': { g: 'c28', v: true, x: -123.213725, y: 48.097485 },
  '-KleKH81yer28MoVfEMW': { g: 'c28', v: true, x: -123.325905, y: 48.106662 },
  '-KleUD0juBdYZeoe_z-q': { g: 'c28', v: true, x: -123.429659, y: 48.119794 },
  '-Klo34L_G5agEOqpbovd': { g: 'c28', v: true, x: -123.396003, y: 48.571614 },
  '-Klo3R9kl7BA75jLv7Xh': { g: 'c28', v: true, x: -123.396094, y: 48.571911 },
  '-KltPx4gNnU0FW9BbRQL': { g: 'c0x', v: true, x: -123.961927, y: 49.149734 },
  '-KltQHHSeS46eRZiEqJ5': { g: 'c0x', v: true, x: -123.962496, y: 49.149894 },
  '-KltZAKh747Wp276lwtv': { g: 'c0x', v: true, x: -124.002884, y: 49.187565 },
  '-KlyGT1ti-2h3Gvj9JTA': { g: 'c0z', v: true, x: -124.446747, y: 49.354767 },
  '-KlyyQ707QUZgJo4raj0': { g: 'c0z', v: true, x: -124.868005, y: 49.548976 },
  '-Klyz0xV1HM4CC1cRkc2': { g: 'c0z', v: true, x: -124.868662, y: 49.550011 },
  '-KmDS0eTTxvcTRyDo6Ey': { g: 'c0z', v: true, x: -123.753916, y: 49.470945 },
  '-KmJ5fZU7FGepOM-Dsd3': { g: 'c28', v: true, x: -123.640735, y: 48.865098 },
  '-KmTUx_PdegkTMa-U0_Q': { g: 'c28', v: true, x: -123.148974, y: 48.515291 },
  '-KoNxTtS9tmuIi5WqSJ0': { g: '9tb', v: true, x: -111.961665, y: 33.487971 },
  '-KomZRSjPvEY32NccKjP': { g: '9tb', v: true, x: -111.938777, y: 33.372255 },
  '-KomZicmIkAugvZoYOFk': { g: '9tb', v: true, x: -111.93924, y: 33.372432 },
  '-Kom_Hkh69ay27Vcvd8g': { g: '9tb', v: true, x: -111.937975, y: 33.372203 },
  '-Kom__PTIp5XegcmBfg-': { g: '9tb', v: true, x: -111.937818, y: 33.372542 },
  '-Kom_x70rXZSp52uAO77': { g: '9tb', v: true, x: -111.937855, y: 33.373511 },
  '-KomaAzSPC3GBSgHxauG': { g: '9tb', v: true, x: -111.938118, y: 33.373924 },
  '-KomaRXxHhL6WhPlEYoY': { g: '9tb', v: true, x: -111.938446, y: 33.374228 },
  '-Komazt-91BrlsyXRBTa': { g: '9tb', v: true, x: -111.937611, y: 33.372948 },
  '-Koo6156pLEDnSX6W2is': { g: '9xh', v: true, x: -105.768036, y: 39.773127 },
  '-Koo6HaacQSYL9WUFHFk': { g: '9xh', v: true, x: -105.608521, y: 39.683015 },
  '-KosfSpl7Jnv0y2Yayue': { g: '9xh', v: true, x: -106.109965, y: 40.074011 },
  '-Kp6Wq6tc54oUKcIoVPY': { g: '9w0', v: true, x: -111.503542, y: 35.064289 },
  '-Kp6X0s4WpIGGxU31nDQ': { g: '9w0', v: true, x: -111.584362, y: 35.111022 },
  '-KpBpkjX2tYoaGbQIkVV': { g: '9w0', v: true, x: -111.852989, y: 34.564051 },
  '-KpBqBS10FM5LFT96yed': { g: '9w0', v: true, x: -111.852024, y: 34.564459 },
  '-KpBrZyra82zHA6jksmE': { g: '9w0', v: true, x: -111.850959, y: 34.549598 }
}

【问题讨论】:

    标签: javascript firebase-realtime-database indexing


    【解决方案1】:

    不需要您代码中的.child('key')。所以:

    var ref = firebase.database().ref().child('markers');
    ref.orderByChild('g').startAt('9tb').on('value', function(snapshot) {
      ...
    

    需要在您执行查询的级别上定义索引,因此对您来说:

    "markers": {
      ".indexOn":"g",
      ...
    },
    

    第三个(希望是最后一个问题)是您没有按顺序显示结果。当您调用 snapshot.val() 时,您会返回一个 JSON 对象,而 JSON 对象中的键根据定义是无序的,因此您最终会按照客户端决定的任何顺序记录它们。

    如果您使用 Firebase 的内置 forEach 方法循环遍历结果,它们将按顺序打印:

    ref.orderByChild('g').startAt('9tb').on('value', function(snapshot) {
      snapshot.forEach(function(child) {
        console.log(child.val());
      });
    });
    

    工作代码:https://jsbin.com/qacefog/2/edit?js,console

    这样,您可以看到它以 9tb 哈希开始,然后移动到 之后 的哈希,这就是 startAt 应该做的。如果您想要以 9tb 开头的地理哈希,则需要包含和 endAt 子句,如下所示:

    ref.orderByChild('g').startAt('9tb').endAt('9tb~')...
    

    这正是 GeoFire 库所做的。

    【讨论】:

    • 谢谢,弗兰克。如果我从“dpt”开始和结束,我会得到所有标记的 Geohash 为“dpt”,但是,如果我只从“dpt”开始并将结果打印到控制台,第一个标记的 Geohash 为“c28” .我曾预计查询会返回所有标记,其 Geohash 为“dpt”,后跟“dpu”等。这是正确的吗?
    • 这似乎确实出乎意料。能否在 jsbin 或 stackblitz 之类的网站上设置复制,让我看看?
    • 当然。是否有一个公共 Firebase 项目,我可以在其中上传一些示例数据以供 JavaScript 访问?或者,我可以将 JSON 数据连同代码一起发送给您。我实际上是在使用 node.js 脚本来测试。
    • 我有一个单独的项目(在免费计划中)为此我已经使用了很多年。如果您将数据共享为文本 JSON,我已经将其添加到那里进行测试。我建议您也自己创建一个这样的项目,或者将数据添加为文本,然后我可以将其添加到我的 stackoverflow 项目中。您可以通过单击Firebase Database console 上溢出菜单 (⠇) 中的“导出 JSON”链接来获取此信息。
    • 我在上面添加了数据、node.js代码和规则。在此示例中搜索“9tb”,但结果相同 - 首先获取“c28”。如果我在 '9tb' 开始和结束,它只返回带有 '9tb' Geohash 的标记。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多