Zapytanie oparte na wielu klauzulach where w Firebase

{
"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"
    }
  }  
 }
Jestem początkującym strażakiem. Jak mogę pobrać wynik z danych powyżej Gdzie genre = 'comedy' i lead = 'Jack Nicholson'?

Jakie mam opcje?

Author: dda, 2014-11-02

3 answers

Używając Firebase ' s new Query API , możesz pokusić się o wypróbowanie tego:

// !!! 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()); 
  });

Ale jak mówi @RobDiMarco z Firebase w komentarzach:

Wiele wywołań orderBy() spowoduje błąd

Więc mój powyższy kod nie zadziała.

Znam trzy podejścia, które będą działać.

1. większość filtrów na serwerze, reszta na kliencie

To co możesz zrobić to wykonać jeden orderBy().startAt()./endAt() na serwerze, ściągnąć Zapisz pozostałe dane i filtruj je w kodzie JavaScript na swoim kliencie.

ref
  .orderBy('genre')
  .equalTo('comedy')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      if (movie.lead == 'Jack Nicholson') {
          console.log(movie);
      }
  });

2. dodaj właściwość, która łączy wartości, na których chcesz filtrować

Jeśli to nie wystarczy, powinieneś rozważyć modyfikację / rozszerzenie danych, aby umożliwić Twój przypadek użycia. Na przykład: możesz wcisnąć genre+lead w jedną właściwość, której właśnie używasz dla tego filtra.

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

Zasadniczo budujesz swój własny indeks wielokolumnowy w ten sposób i możesz go odpytywać z:

ref
  .orderBy('genre_lead')
  .equalTo('comedy_Jack Nicholson')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      console.log(movie);
  });

David East napisał bibliotekę o nazwie QueryBase, która pomaga w generowaniu takich właściwości .

Możesz nawet wykonywać zapytania względne / zakresowe, powiedzmy, że chcesz zezwolić na odpytywanie filmów według kategorii I roku. Możesz użyć tej struktury danych:

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

A następnie Zapytanie o komedie z Lat 90-tych z:

ref
  .orderBy('genre_year')
  .startAt('comedy_1990')
  .endAt('comedy_2000')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      console.log(movie);
  });

Jeśli chcesz filtrować więcej niż tylko rok, pamiętaj, aby dodać inne części daty w kolejności malejącej, np. "comedy_1997-12-25". W ten sposób porządkowanie leksykograficzne, które Firebase robi na wartościach łańcuchowych, będzie takie samo jak porządkowanie chronologiczne.

Ta kombinacja wartości we właściwości może działać z więcej niż dwiema wartościami, ale można wykonać filtr zakresu tylko dla ostatniej wartości we właściwości złożonej.

[10]}bardzo specjalny wariant tego jest zaimplementowany przez bibliotekę GeoFire dla Firebase. Biblioteka ta łączy szerokość i długość geograficzną danej lokalizacji w tzw. [53]}Geohash , który może być następnie użyty do wykonywania zapytań o zasięg w czasie rzeczywistym w Firebase.

3. tworzenie indeksu niestandardowego programowo

Jeszcze inną alternatywą jest zrobienie tego, co wszyscy zrobiliśmy przed dodaniem nowego API zapytań: Utwórz indeks w innym węźle:

  "movies"
      // the same structure you have today
  "by_genre"
      "comedy"
          "by_lead"
              "Jack Nicholson"
                  "movie1"
              "Jim Carrey"
                  "movie3"
      "Horror"
          "by_lead"
              "Jack Nicholson"
                  "movie2"

Jest prawdopodobnie więcej podejść. Na przykład, ta odpowiedź podkreśla alternatywny indeks niestandardowy w kształcie drzewa: https://stackoverflow.com/a/34105063

 176
Author: Frank van Puffelen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-18 16:42:16

Napisałem osobistą bibliotekę, która pozwala zamawiać według wielu wartości, a wszystkie zamówienia wykonywane są na serwerze.

Poznaj Querybase!

Querybase pobiera odniesienie do bazy danych Firebase i tablicę pól, na których chcesz się zindeksować. Podczas tworzenia nowych rekordów automatycznie będzie obsługiwać generowanie kluczy, które pozwalają na wielokrotne zapytania. Zastrzeżenie jest takie, że obsługuje tylko równoważność prostą (nie mniejszą lub większą niż).

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));
 30
Author: David East,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-06 13:38:41
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) {

    }
});
 2
Author: Andrew Lam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-04 08:19:40