Consulta basada en múltiples cláusulas donde en Firebase

Resuelto 47d_ asked hace 54 años • 8 respuestas
{
  "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 en Firebase. ¿Cómo puedo recuperar un resultado de los datos anteriores donde genre = 'comedy'ANDlead = 'Jack Nicholson' ?

¿Que opciones tengo?

47d_ avatar Jan 01 '70 08:01 47d_
Aceptado

Al usar la Query API 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 orderBy()llamadas arrojarán un error

Entonces mi código anterior no funcionará .

Conozco tres enfoques que funcionarán.

1. filtrar la mayor parte en el servidor, hacer el resto en el cliente

Lo que puede hacer es ejecutar uno orderBy().startAt()./endAt()en el servidor, extraer los datos restantes y filtrarlos en código JavaScript en 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/ampliar sus datos para permitir su caso de uso. Por ejemplo: podría incluir género+cliente principal en una sola propiedad que solo use para este filtro.

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

Básicamente, estás creando tu propio índice de varias columnas de esa manera y puedes 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 dichas propiedades .

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

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

Y luego consulta por 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 algo 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 manera, el orden lexicográfico que Firebase realiza en los valores de las cadenas 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 realizar un filtro de rango en el último valor de la propiedad compuesta.

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

Tercero, cree un índice personalizado mediante programación

Otra alternativa más es hacer lo que todos hemos hecho antes de que se agregara 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 destaca un índice personalizado alternativo en forma de árbol: https://stackoverflow.com/a/34105063


Si ninguna de estas opciones te funciona, pero aún deseas almacenar tus datos en Firebase, también puedes considerar usar su base de datos Cloud Firestore .

Cloud Firestore puede manejar varios filtros de igualdad en una sola consulta, pero solo un filtro de rango. Básicamente, utiliza el mismo modelo de consulta, pero es como si generara automáticamente las propiedades compuestas por usted. Consulte la documentación de Firestore sobre consultas compuestas .

Frank van Puffelen avatar Nov 02 '2014 16:11 Frank van Puffelen

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

¡Conoce Querybase!

Querybase incluye una referencia de la base de datos de Firebase y una serie de campos que desea indexar. Cuando crea nuevos registros, manejará automáticamente la generación de claves que permiten consultas múltiples. La advertencia es que solo admite equivalencia directa (ni menor ni 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));
David East avatar Jun 06 '2016 13:06 David East