web-dev-qa-db-fra.com

Requête basée sur plusieurs clauses where dans 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"
    }
  }  
 }

Je suis un débutant Firebase. Comment puis-je récupérer un résultat à partir des données ci-dessus genre = 'comedy' AND lead = 'Jack Nicholson'?

Quelles sont mes options?

218
47d_

En utilisant API de requête de Firebase , vous pourriez être tenté d'essayer ceci:

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

Mais comme le dit @RobDiMarco de Firebase dans les commentaires:

plusieurs appels orderBy() généreront une erreur

Donc mon code ci-dessus ne fonctionnera pas .

Je connais trois approches qui fonctionneront.

1. filtrer le plus sur le serveur, faire le reste sur le client

Ce que vous pouvez faire, c'est exécuter un orderBy().startAt()./endAt() sur le serveur, déroulez les données restantes et filtrez-le dans le code JavaScript de votre client.

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

2. ajoutez une propriété qui combine les valeurs que vous souhaitez filtrer

Si cela ne suffit pas, vous devriez envisager de modifier/développer vos données pour permettre votre cas d'utilisation. Par exemple: vous pouvez insérer genre + lead dans une propriété unique que vous utilisez simplement pour ce filtre.

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

Vous construisez ainsi votre propre index multi-colonnes et pouvez l'interroger avec:

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

David East a écrit un bibliothèque appelée QueryBase qui aide à générer de telles propriétés .

Vous pouvez même faire des requêtes relatives/plage, disons que vous voulez autoriser l’interrogation de films par catégorie et par année. Vous utiliseriez cette structure de données:

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

Et ensuite, recherchez les comédies des années 90 avec:

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

Si vous devez filtrer sur plus que l'année, veillez à ajouter les autres éléments de date dans l'ordre décroissant, par exemple. "comedy_1997-12-25". Ainsi, l'ordre lexicographique que Firebase applique aux valeurs de chaîne sera le même que l'ordre chronologique.

Cette combinaison de valeurs dans une propriété peut fonctionner avec plus de deux valeurs, mais vous ne pouvez effectuer un filtre de plage que sur la dernière valeur de la propriété composite.

Une variante très spéciale de ceci est implémentée par le bibliothèque GeoFire pour Firebase . Cette bibliothèque combine la latitude et la longitude d'un emplacement dans un soi-disant Geohash , qui peut ensuite être utilisé pour effectuer des requêtes en temps réel sur Firebase.

3. créer un index personnalisé par programme

Une autre alternative consiste à faire ce que nous avons tous fait avant l’ajout de cette nouvelle API de requête: créer un index dans un autre noeud:

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

Il y a probablement plus d'approches. Par exemple, cette réponse met en évidence un autre index personnalisé en forme d’arbre: https://stackoverflow.com/a/3410506

212

J'ai écrit une bibliothèque personnelle qui vous permet de commander par plusieurs valeurs, avec toutes les commandes effectuées sur le serveur.

Meet Querybase!

Querybase prend en référence une base de données Firebase et un tableau de champs que vous souhaitez indexer. Lorsque vous créez de nouveaux enregistrements, la génération de clés permettant plusieurs requêtes est automatiquement traitée. La mise en garde est qu'il ne prend en charge que l'équivalence directe (pas moins que ou plus grand 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));
41
David East
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
Andrew Lam Yat Weng
ref.orderByChild("lead").startAt("Jack Nicholson").endAt("Jack Nicholson").listner....

Cela fonctionnera.

0
jaleel