首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Firebase中基于多where子句的查询

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

Stack Overflow用户
提问于 2014-11-02 23:25:45
回答 8查看 214.3K关注 0票数 281
{
  "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' lead = 'Jack Nicholson'上的数据中检索结果

我有什么选择?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2014-11-03 00:00:53

使用Firebase's 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()调用将抛出错误

所以我上面的代码将不会在中工作。

我知道有三种方法是可行的。

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

大卫·伊斯特写了一个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.以编程方式创建自定义索引

另一种选择是做我们在添加这个新的查询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 database

Cloud Firestore可以在一个查询中处理多个相等过滤器,但只能处理一个范围过滤器。在幕后,它本质上使用相同的查询模型,但它像是自动为您生成复合属性。请参阅compound queries上的Firestore文档。

票数 270
EN

Stack Overflow用户

发布于 2016-06-06 21:38:41

我已经编写了一个个人库,它允许您按多个值排序,所有的排序都在服务器上完成。

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));
票数 56
EN

Stack Overflow用户

发布于 2016-01-20 22:22:02

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) {

    }
});
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26700924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档