基于firebase中多个where子句的查询

{ "movies": { "movie1": { "genre": "comedy", "name": "As good as it gets", "lead": "Jack Nicholson" }, "movie2": { "genre": "Horror", "name": "The Shining", "lead": "Jack Nicholson" }, "movie3": { "genre": "comedy", "name": "The Mask", "lead": "Jim Carrey" } } } 

我是Firebase新手。 如何从上面的数据中检索genre = 'comedy' AND lead = 'Jack Nicholson'

我有什么select?

使用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.添加一个属性,结合您想要过滤的值

如果这还不够好,你应该考虑修改/扩展你的数据以允许你的用例。 例如:你可以将stream派+主angular引入一个单一的属性,你只是用这个filter。

 "movie1": { "genre": "comedy", "name": "As good as it gets", "lead": "Jack Nicholson", "genre_lead": "comedy_Jack Nicholson" },... 

你本质上是build立你自己的多列索引,并可以查询它:

 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); }); 

如果您需要过滤一年以上,请确保按降序添加其他date部分,例如"comedy_1997-12-25" 。 通过这种方式,Firebase在string值上的字典顺序将与时间顺序相同。

这种属性值的组合可以使用两个以上的值,但只能对组合属性中的最后一个值进行范围过滤。

Firebase的GeoFire库实现了一个非常特殊的变体。 该库将位置的经度和纬度组合成一个所谓的Geohash ,然后可用于在Firebase上进行实时范围查询。

3.以编程方式创build自定义索引

还有另一种方法是在添加新的查询API之前完成所有工作:在不同的节点中创build一个索引:

  "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

我已经写了一个个人图书馆,允许您通过多个值进行sorting,并在服务器上完成所有sorting。

满足查询库!

Querybase引入了一个Firebase数据库引用和一系列您想要索引的字段。 当您创build新logging时,它将自动处理允许多个查询的密钥的生成。 需要注意的是,它只支持直接等价(不小于或大于)。

 const databaseRef = firebase.database().ref().child('people'); const querybaseRef = querybase.ref(databaseRef, ['name', 'age', 'location']); // Automatically handles composite keys querybaseRef.push({ name: 'David', age: 27, location: 'SF' }); // Find records by multiple fields // returns a Firebase Database ref const queriedDbRef = querybaseRef .where({ name: 'David', age: 27 }); // Listen for realtime updates queriedDbRef.on('value', snap => console.log(snap)); 
 var ref = new Firebase('https://your.firebaseio.com/'); Query query = ref.orderByChild('genre').equalTo('comedy'); query.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { for (DataSnapshot movieSnapshot : dataSnapshot.getChildren()) { Movie movie = dataSnapshot.getValue(Movie.class); if (movie.getLead().equals('Jack Nicholson')) { console.log(movieSnapshot.getKey()); } } } @Override public void onCancelled(FirebaseError firebaseError) { } });