使用Firebase的查询API,你可能会尝试这样做:
// !!! THIS WILL NOT WORK !!!
ref
.orderBy('genre')
.startAt('comedy').endAt('comedy')
.orderBy('lead') // !!! THIS LINE WILL RAISE AN ERROR !!!
.startAt('Jack Nicholson').endAt('Jack Nicholson')
.on('value', function(snapshot) {
console.log(snapshot.val());
});
但正如Firebase的@RobDiMarco在评论中所说:
多次orderBy()调用将抛出一个错误
所以我上面的代码将无法工作。
我知道有三种可行的方法。
1. 在服务器上过滤大部分,在客户端上完成其余部分
您所能做的就是在服务器上执行一个orderBy(). startat ()./endAt(),下拉剩下的数据并在客户端上的JavaScript代码中进行筛选。
ref
.orderBy('genre')
.equalTo('comedy')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
if (movie.lead == 'Jack Nicholson') {
console.log(movie);
}
});
2. 添加一个属性,该属性组合了要筛选的值
如果这还不够好,您应该考虑修改/扩展您的数据以支持您的用例。例如:你可以将genre+lead填充到一个属性中,只用于这个过滤器。
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson",
"genre_lead": "comedy_Jack Nicholson"
}, //...
你实际上是在用这种方式建立你自己的多列索引,并可以使用:
ref
.orderBy('genre_lead')
.equalTo('comedy_Jack Nicholson')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
console.log(movie);
});
David East编写了一个名为QueryBase的库,可以帮助生成这样的属性。
你甚至可以做相对/范围查询,比方说你想允许按类别和年份查询电影。你可以使用这样的数据结构:
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson",
"genre_year": "comedy_1997"
}, //...
然后查询90年代的喜剧:
ref
.orderBy('genre_year')
.startAt('comedy_1990')
.endAt('comedy_2000')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
console.log(movie);
});
如果你需要过滤的不仅仅是年份,请确保按降序添加其他日期部分,例如:“comedy_1997-12-25”。这样,Firebase对字符串值进行的字典顺序将与时间顺序相同。
属性中值的这种组合可以用于两个以上的值,但只能对复合属性中的最后一个值进行范围筛选。
一个非常特殊的变体是由Firebase的GeoFire库实现的。这个库将一个位置的经纬度结合到一个所谓的Geohash中,然后可以用于在Firebase上进行实时范围查询。
3.以编程方式创建自定义索引
还有一种替代方法是做我们在添加这个新的查询API之前都做过的事情:在不同的节点上创建索引:
"movies"
// the same structure you have today
"by_genre"
"comedy"
"by_lead"
"Jack Nicholson"
"movie1"
"Jim Carrey"
"movie3"
"Horror"
"by_lead"
"Jack Nicholson"
"movie2"
可能有更多的方法。例如,这个答案突出显示了另一个树形自定义索引:https://stackoverflow.com/a/34105063
如果这些选项都不适合你,但你仍然想将数据存储在Firebase中,你也可以考虑使用它的Cloud Firestore数据库。
Cloud Firestore可以在一个查询中处理多个相等过滤器,但只能处理一个范围过滤器。本质上,它使用相同的查询模型,但它为您自动生成复合属性。请参阅Firestore关于复合查询的文档。