web-dev-qa-db-ja.com

FireBaseでorderByChildが機能しない

子キーに基づいて順序付けられたリストを取得するようにデータベースを照会しようとしています。私はそれを次のように行いますが(以下を参照)、何も起こりません。つまり、Firebaseデータベースに保存されているのとまったく同じ方法で順序付けられたオブジェクトを返します。何が起こっている?

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

追加するには、ユーザーノードは次のようになります。

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

スナップショットは次のとおりです。

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

snapshot.val()を呼び出すと、JSONオブジェクトが返されます。 JSONオブジェクト内のキーの順序は、Firebaseではなくブラウザーによって決定されます。

子を順番に取得するには:

_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;
};
_

q.resolve()呼び出しはそのままにしておくことができます。snapshot.forEach()は非同期呼び出しではありません。

81

この質問に対する回答は1年以上前のものですが、コメントセクションにはまだ混乱があるため、情報を追加したいと思います。

問題

元の問題は、OPがFirebaseリアルタイムデータベースの子キーに基づいて順序付けられたリストを取得したいが、.orderByChild('arg')が期待どおりに機能しないことです。

しかし、期待どおりに機能しなかったのは.orderByChild('arg')ではなく、.on("value", callback)です。 .on("value", callback)は、.on("child_added", callback)のような他のeventTypeとは少し異なるためです。

以下のように、firebaseリアルタイムデータベースがあるとします。

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

-

.on("value", callback)を使用すると、callback()が1回呼び出され、3つのオブジェクトのオブジェクト配列を返します。

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

enter image description here

-

.on("child_added", callback)を使用すると、callback()が3回呼び出され、毎回Objectが返され、順番にが返されます

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

enter image description here

結論

Firebaseから順序付けられたデータのみを取得する必要がある場合(たとえば、UIを初期化する場合)、ref.orderByChild('arg').once("child_added", callback)が適切です。これはシンプルで使いやすいです。

ただし、何らかの理由でref.orderByChild('arg').on("value", callback)を使用する必要がある場合は、Frank van Puffelenの答えを参照してください。

参照

on(eventType, callback, cancelCallbackOrContext, context)、引数、戻り値の詳細については、 Firebase Document をお読みください。

別の便利なドキュメント: Web上のデータのリストを操作する

15
user2875289

valueイベントリスナーを使用した注文の場合:

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

順序を逆にする場合は、次を試してください。

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

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

  return reversed;
}

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

参照してください: https://firebase.google.com/docs/database/web/lists-of-data#listen_for_value_events

3
Renan Coelho

IOSでも同じ問題に苦労しました。スナップショットをNSDictionaryオブジェクトに変換すると、順序なしリストに変換されます。必要な場合のObjective-cバージョン:

[[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;      
     } 
}];