首页 文章

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

提问于
浏览
189
{
"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的新手 . 如何从 where genre = 'comedy' AND lead = 'Jack Nicholson' 上方的数据中检索结果?

我有什么选择?

4 回答

  • 32

    使用Firebase's new Query 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()调用将引发错误

    所以 my code above will not work .

    我知道有三种方法可行 .

    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.添加一个属性,该属性组合了您要过滤的值

    如果这还不够好,您应该考虑修改/扩展您的数据以允许您的用例 . 例如:您可以将类型导联填充到您刚刚用于此过滤器的单个属性中 .

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

    大卫东写了一篇library called QueryBase that helps with generating such properties .

    您甚至可以进行相对/范围查询,假设您希望允许按类别和年份查询电影 . 您将使用此数据结构:

    "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对字符串值执行的词典排序将与按时间顺序排列相同 .

    属性中值的组合可以使用两个以上的值,但是您只能对复合属性中的最后一个值执行范围过滤 .

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

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

    另一种方法是在添加新的Query 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

  • 187
    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) {
    
        }
    });
    
  • 0

    我写了一个个人库,允许您按多个值排序,所有订单都在服务器上完成 .

    认识Querybase!

    Querybase接收Firebase数据库引用和您要索引的字段数组 . 当您创建新记录时,它将自动处理允许多次查询的密钥的生成 . 需要注意的是,它只支持直接等价(不小于或大于) .

    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));
    
  • 2
    ref.orderByChild("lead").startAt("Jack Nicholson").endAt("Jack Nicholson").listner....
    

    这会奏效 .

相关问题