286
{
  "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 の初心者です。ANDの上genre = 'comedy'lead = 'Jack Nicholson'データから結果を取得するにはどうすればよいですか?

どのようなオプションがありますか?

4

8 に答える 8

277

Firebase の 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()呼び出しはエラーをスローします

したがって、上記のコードは機能しません

私はうまくいく3つのアプローチを知っています。

1. ほとんどをサーバーでフィルタリングし、残りはクライアントで行います

できることは、サーバーで 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. フィルタリングする値を組み合わせたプロパティを追加します

それが十分でない場合は、ユースケースを許可するようにデータを変更/拡張することを検討する必要があります。例: ジャンル + リードを、このフィルターに使用する 1 つのプロパティに詰め込むことができます。

"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 が文字列値に対して行う辞書式の順序は、時系列の順序と同じになります。

プロパティ内の値のこの組み合わせは、3 つ以上の値で機能しますが、複合プロパティ内の最後の値に対してのみ範囲フィルターを実行できます。

これの非常に特殊なバリアントが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 は、1 つのクエリで複数の等価フィルタを処理できますが、範囲フィルタは 1 つだけです。内部的には基本的に同じクエリ モデルを使用しますが、複合プロパティを自動生成するように見えます。複合クエリに関する Firestore のドキュメントを参照してください。

于 2014-11-02T16:00:52.953 に答える
56

サーバー上ですべての順序付けを行い、複数の値で順序付けできるようにする個人用ライブラリを作成しました。

クエリベースに会いましょう!

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));
于 2016-06-06T13:38:41.443 に答える