Consulta basada en múltiples cláusulas Where en 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" } } } 

Soy un novato de Firebase. ¿Cómo puedo recuperar un resultado de los datos de arriba donde genre = 'comedy' AND lead = 'Jack Nicholson' ?

¿Que opciones tengo?

Con la nueva API de consulta de Firebase , es posible que tengas la tentación de probar esto:

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

Pero como dice @RobDiMarco de Firebase en los comentarios:

varias llamadas a orderBy() arrojarán un error

Entonces mi código anterior no funcionará .

Conozco tres enfoques que funcionarán.

1. filtrar la mayoría en el servidor, hacer el rest en el cliente

Lo que puede hacer es ejecutar one orderBy().startAt()./endAt() en el servidor, desplegar los datos restantes y filtrarlos en el código JavaScript de su cliente.

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

2. agregue una propiedad que combine los valores que desea filtrar

Si eso no es lo suficientemente bueno, debería considerar modificar / expandir sus datos para permitir su uso-caso. Por ejemplo: puedes incluir género + plomo en una sola propiedad que acabas de usar para este filtro.

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

En esencia, está construyendo su propio índice de varias columnas de esa manera y puede consultarlo con:

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

David East ha escrito una biblioteca llamada QueryBase que ayuda a generar tales propiedades .

Incluso podría hacer consultas relativas / de rango, digamos que desea permitir consultas de películas por categoría y año. Utilizarías esta estructura de datos:

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

Y luego consulta las comedias de los 90 con:

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

Si necesita filtrar más que solo el año, asegúrese de agregar las otras partes de la fecha en orden descendente, por ejemplo, "comedy_1997-12-25" . De esta forma, el orden lexicográfico que Firebase hace sobre los valores de cadena será el mismo que el orden cronológico.

Esta combinación de valores en una propiedad puede funcionar con más de dos valores, pero solo puede hacer un filtro de rango en el último valor en la propiedad compuesta.

Una variante muy especial de esto es implementada por la biblioteca de GeoFire para Firebase . Esta biblioteca combina la latitud y la longitud de una ubicación en un llamado Geohash , que luego se puede usar para hacer consultas de rango en tiempo real en Firebase.

3. crear un índice personalizado programáticamente

Otra alternativa más es hacer lo que todos hemos hecho antes de agregar esta nueva API de consulta: crear un índice en un nodo diferente:

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

Probablemente haya más enfoques. Por ejemplo, esta respuesta resalta un índice personalizado alternativo en forma de árbol: https://stackoverflow.com/a/34105063

He escrito una biblioteca personal que le permite ordenar por múltiples valores, con todos los pedidos realizados en el servidor.

Conoce Querybase!

Querybase toma una referencia de base de datos de Firebase y una matriz de campos en los que desea indexar. Cuando crea nuevos registros, gestionará automáticamente la generación de claves que permiten múltiples consultas. La advertencia es que solo admite equivalencia directa (no menor o mayor que).

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