Firebase の複数の where 句に基づくクエリ 質問する

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

どのような選択肢がありますか?

ベストアンサー1

使用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()呼び出しはエラーが発生します

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

うまくいくアプローチが 3 つあるとわかっています。

1. サーバー上で大部分のフィルタリングを行い、残りはクライアント上で行う

できることは、orderBy().startAt()./endAt()サーバー上で1 つ実行し、残りのデータを取得して、クライアント上の 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);
  });

デイビッド・イーストはこのようなプロパティを生成するのに役立つ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 が文字列値に対して行う辞書式順序は、時系列順序と同じになります。

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

この非常に特殊なバリエーションは、Firebase 用 GeoFire ライブラリこのライブラリは、場所の緯度と経度をいわゆるジオハッシュこれを使用して、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にデータを保存したい場合は、Firebaseの使用も検討してください。Cloud Firestore データベース

Cloud Firestoreは、1つのクエリで複数の等式フィルタを処理できますが、範囲フィルタは1つしか処理できません。内部的には基本的に同じクエリモデルを使用していますが、複合プロパティを自動生成するようなものです。Firestoreのドキュメントを参照してください。複合クエリ

おすすめ記事