web-dev-qa-db-fra.com

orderByChild ne fonctionne pas dans Firebase

J'essaie d'interroger ma base de données de telle sorte qu'elle récupère une liste ordonnée basée sur une clé enfant. Je le fais comme suit (voir ci-dessous), mais rien ne se produit, ce qui signifie qu'il renvoie un objet commandé exactement de la même manière qu'il est stocké dans la base de données Firebase. Que se passe-t-il?

self.getAllProfiles = function () {
    var qProfile = $q.defer();
    var ref = new Firebase(FBURL);
    ref.child("users").orderByChild('last_update').on("value", function (snapshot) {
        console.log(snapshot.val()) // HERE IS WHERE IT SHOULD BE ORDERED
        qProfile.resolve(snapshot.val());
    }, function (errorObject) {
        qProfile.reject(errorObject);
    });
    return qProfile.promise;
};

Pour ajouter, mon noeud utilisateurs ressemble à ceci:

users
   /$username
       /last_update
       /id
       /data
          /profile_image
          /display_name

Voici un aperçu:

Tester: Object
   github: Object
   last_update: 1447732462170
   userId: "github:12345"
25
JohnAndrews

Lorsque vous appelez snapshot.val(), vous récupérez un objet JSON. L'ordre des clés dans un objet JSON est déterminé par votre navigateur et non par Firebase. 

Pour mettre les enfants en ordre:

self.getAllProfiles = function () {
    var qProfile = $q.defer();
    var ref = new Firebase(FBURL);
    ref.child("users").orderByChild('last_update').on("value", function (snapshot) {
        snapshot.forEach(function(child) {
            console.log(child.val()) // NOW THE CHILDREN PRINT IN ORDER
        });
        qProfile.resolve(snapshot.val());
    }, function (errorObject) {
        qProfile.reject(errorObject);
    });
    return qProfile.promise;
};

Vous pouvez laisser l'appel q.resolve() tel qu'il est: snapshot.forEach() n'est pas un appel asynchrone.

73
Frank van Puffelen

Je sais que cette question a été répondue et a plus d'un an, mais comme il y a encore une certaine confusion dans la section commentaire, j'aimerais ajouter quelques informations.

Le problème

Le problème initial est que l'OP souhaite récupérer une liste ordonnée basée sur une clé enfant de la base de données en temps réel Firebase, mais la fonction .orderByChild('arg') ne fonctionne pas comme prévu.

Mais ce qui n'a pas fonctionné comme prévu n'est pas .orderByChild('arg'), mais .on("value", callback). Parce que .on("value", callback) fonctionne un peu différemment des autres eventTypes comme .on("child_added", callback).

Exemple

Disons que nous avons une base de données en temps réel firebase comme ci-dessous:

{
    myData: {
        -KYNMmYHrzLcL-OVGiTU: {
             NO: 1,
             image: ...
        },
        -KYNMwNIz4ObdKJ7AGAL: {
             NO: 2,
             image: ...
        },
        -KYNNEDkLpuwqQHSEGhw: {
             NO: 3,
             image: ...
        },
    }
}

-

Si nous utilisons .on("value", callback), le callback () sera appelé 1 fois et retournera un tableau d'objets de 3 objets.

ref.on("value", function(snapshot) {
    console.log(snapshot.val());
    // Please see Frank van Puffelen's answer
}

 enter image description here

-

Si nous utilisons .on("child_added", callback), le callback () sera appelé 3 fois, à chaque fois retourne un objet, et ils sont retournés dans l'ordre.

ref.once("child_added", function(snapshot) { 
    console.log(snapshot.val());
    // The objects are returned in order, do whatever you like
}

 enter image description here

Conclusion

Si vous avez seulement besoin d'extraire les données ordonnées de firebase (par exemple, pour initialiser l'interface utilisateur), alors ref.orderByChild('arg').once("child_added", callback) vous ira bien, c'est simple et facile à utiliser.

Cependant, si pour une raison quelconque vous devez utiliser ref.orderByChild('arg').on("value", callback), veuillez vous reporter à la réponse de Frank van Puffelen.

Référence

Veuillez lire Document Firebase pour plus d’informations sur on(eventType, callback, cancelCallbackOrContext, context), leurs arguments et leurs valeurs de retour.

Autre document utile: Travailler avec des listes de données sur le Web

13
user2875289

Pour commander à l'aide de l'écouteur d'événements value:

firebase.database().ref('/invoices').orderByChild('name').on('value', snapshot => {
    snapshot.forEach(child => {
        console.log(child.key, child.val());
    });
}

Si vous voulez inverser l'ordre, essayez:

function reverseSnapshotOrder (snapshot) {
  let reversed = [];

  snapshot.forEach(child => {
    reversed.unshift(child);
  });

  return reversed;
}

reverseSnapshotOrder(snapshot).forEach(child => {
  console.log(child.key, child.val());
});

Veuillez consulter: https://firebase.google.com/docs/database/web/lists-of-data#listen_for_value_events

2
Renan Coelho

Je me suis battu avec le même problème dans iOS. Si vous convertissez un instantané en objet NSDictionary, celui-ci est converti en liste non ordonnée. Version Objective-c en cas de besoin:

[[self.refChild queryOrderedByChild:@"date_created"] 
  observeEventType:FIRDataEventTypeValue 
         withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {

     for (FIRDataSnapshot *child in snapshot.children) {  

          NSDictionary *anObject = child.value; 
          NSString *aKey         = child.key;      
     } 
}];
0