这是场景:
1)我有一个移动应用程序,它有两个数据点:位置和主题标题.
2)我将这两点发送给firebase.
3)从具有不同位置和不同主题的各种设备发送许多点.
4)移动设备然后请求特定位置的主题标题列表.
我的问题是:在将集合返回给调用者之前,firebase可以在数据库中按字母顺序自动重新排序这些主题标题吗?
从本质上讲,我不希望移动设备重新排序任何内容,只是直接从数据集中显示数据.
我想这必须在服务器端用Javascript代码完成,我不清楚它是如何在firebase中完成的.
提前致谢
1> Frank van Pu..:
看起来你有一个非常好的用例,但我不会尝试将它转换为适合你的工作应用程序.相反,我会提供一些指向最重要部分的指针,它们与Firebase有关.
数据结构
假设您将此结构用于您的兴趣点:
locations
-123981234cbdag
title: "White House"
latitude: 38.897676
longitude: -77.036528
-458614tajsla12
title: "Google San Francisco"
latitude: 37.789635
longitude: -122.390375
此代码段中位置的名称/键("-123981234cbdag"和"-458614tajsla12")具有Firebase在调用其push
方法时生成的格式.
以特定顺序从Firebase检索数据
Firebase可以按任何顺序为您的应用程序提供位置:
通过他们的钥匙(当你使用时也按时间顺序push
)
按他们的优先级(在上面的例子中没有显示)
由任何儿童财产的价值
每个代码:
// we call this helper function below to print the locations
function printSnapshot(locations) {
locations.forEach(function(snapshot) {
console.log(snapshot.val().title);
});
}
var ref = new Firebase('https://your.firebaseio.com/locations');
// 1a. gives a snapshot with the children in order of their key
ref.on('value', printSnapshot);
// 1b. the same result, but explicitly orders the keys in order of their name
ref.orderByKey().on('value', printSnapshot);
// 2. gives a snapshot with the children in the order of their priority
ref.orderByPriority().on('value', printSnapshot);
// 3a. gives a snapshot with the children in the order of their title
ref.orderByChild('title').on('value', printSnapshot);
// 3b. gives a snapshot with the children in the order of their latitude
ref.orderByChild('latitude').on('value', printSnapshot);
// 3c. gives a snapshot with the children in the order of their longitude
ref.orderByChild('longitude').on('value', printSnapshot);
订购数据后,您还可以限制检索的内容.
检索较少的可用位置
这个片段将回归白宫:
ref.orderByChild('title').equalTo('White House').on('value', printSnapshot);
这段代码也是如此:
ref.orderByChild('title').limitToLast(1).on('value', printSnapshot);
但是,一旦您的一位用户访问锡安国家公园,这最后可能会返回不同的位置.另外值得注意的是,最后一段代码会自动收到Firebase中可能显示的任何新值,因为Firebase会主动同步符合您查询的数据.
所以流程可能是:
您的应用程序已启动
它运行上面的查询,询问按标题排序时的最后位置
Firebase将白宫位置发送到您的应用程序,应用程序显示该应用程序
有人访问锡安国家公园并将数据插入Firebase
Firebase将锡安国家公园的位置发送到您的应用程序
等等
按纬度或经度过滤
好的,我们在这里分心了一点.让我们回到你的用例.我假设您知道用户的位置,但如果您不知道,请查看此问题.
var whereAmI = { latitude: 38.898042, longitude: -77.03326};
如果有人确切地添加了该用户所在的位置,我们可以equalTo
像以前一样使用.但考虑到GPS设备的精度不同,这将不太可靠.因此,我们应该检查附近的位置,以便在我们的纬度/经度的某个范围内.
我们可以使用Firebase startAt
和endAt
方法:
ref
.orderByChild('latitude')
.startAt(whereAmI.latitude - 0.002)
.endAt(whereAmI.latitude + 0.002)
.on('value', printSnapshot);
这个片段将返回位于您所在位置的东部或西部几百米范围内的位置,其中......猜测......在我们的样本数据集中只是白宫!
如果我们坚持limitToFirst(1)
下去,它甚至会限制返回的地点数量.但不幸的是,它将返回最东部的位置,这不一定是最接近我的位置.(我对纬度不是很好,也可能是最西边的地方)此外,它只适合纬度; 您还想使用经度来查找位于您北方或南方的位置.
理想情况下,您可以在Firebase中执行以下操作:
// !!!THIS IS A NON-WORKING EXAMPLE!!!
ref
.orderByChild('latitude')
.startAt(whereAmI.latitude - 0.002)
.endAt(whereAmI.latitude + 0.002)
.orderByChild('longitude')
.startAt(whereAmI.longitude- 0.002)
.endAt(whereAmI.longitude+ 0.002)
.on('value', printSnapshot);
// !!!THIS IS A NON-WORKING EXAMPLE!!!
但遗憾的是,Firebase目前每个查询只能过滤一个孩子.因此,要么我们必须检索地球的整个纬度切片中的所有子项并过滤客户端,要么我们必须找到一种方法将纬度和经度填充到单个属性中,该属性还保持良好的"它可以轻松排序"属性数字.
输入"Geohashes"和GeoFire.
由Geohash过滤(使用Geofire)
如果您访问Firebase的实时公共交通信息演示,您将看到与您的用例非常接近的内容.它显示了某个地区的所有MUNI(旧金山公共交通)线路.
从手机屏幕截图,因为我无法从桌面界面找到一个(无论如何它看起来非常相似)
如果您等待几秒钟(并且在营业时间内访问),您甚至会看到车辆四处移动.他们展示的区域是一个圆圈,所以编写该演示的人都清楚地知道如何查询纬度和经度.
他们使用的技巧称为Geohashing并引用维基百科:
它是一种分层空间数据结构,它将空间细分为网格形状的桶.
Geohashes提供了诸如任意精度之类的属性,并且可以逐渐从代码末尾删除字符以减小其大小(并逐渐失去精度).
由于逐渐精确度降低,附近的地方通常(但不总是)呈现类似的前缀.共享前缀越长,两个位置越接近.
这就像你的应用程序的秘密酱一样:geohash将纬度和经度编码为单个值,可以订购.我建议玩一下geohashes.由于最初的geohash.org似乎失败了,我使用了openlocation.org的Geohash服务.它甚至在白宫周围开始,并显示我们的位置在这些Geohashes周围的某处:('dqcm0n','dqcm0h','dqcm0m','dqcjpv','dqcjpy','dqcm0q','dqcm0k','dqcjpu','dqcm0j')
Firebase的工作人员也意识到这将非常有用,因此他们创建了一个名为Geofire的帮助库.在Firebase的网站上有一个很棒的GeoFire介绍和教程.我建议你继续在那里工作.