orderByChild не работает в Firebase

Я пытаюсь запросить свою базу данных, чтобы получить упорядоченный список на основе дочернего ключа. Я делаю это следующим образом (см. Ниже), но ничего не происходит, что означает, что он возвращает объект, упорядоченный точно так же, как он хранится в базе данных 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"

person JohnAndrews    schedule 24.11.2015    source источник
comment
Можете ли вы показать свои данные неупорядоченными, а затем как они будут выглядеть, когда они вернутся в виде снимка?   -  person David East    schedule 24.11.2015
comment
Обновил вопрос со снимком   -  person JohnAndrews    schedule 24.11.2015
comment
Трудно сказать, что происходит с предоставленными вами данными. Можете ли вы создать JSBin, демонстрирующий вашу проблему? Это значительно упростило бы поиск и устранение неисправностей.   -  person David East    schedule 24.11.2015
comment
Скорее всего ответ ниже. Но, как сказал Дэвид: подумайте о создании JSBin / JsFiddle в следующий раз, поскольку он предоставит минимальный, полный пример. Одна вещь, которой сейчас не хватает, - это достаточно данных, чтобы понять, что вы видите и почему это может быть (всегда непростой баланс между «минимальным» и «полным»).   -  person Frank van Puffelen    schedule 24.11.2015
comment
Убедитесь, что вы действительно просматриваете дочерние снимки. Если вы просто распечатаете снимок, он будет упорядочен как стандартный JSON, а не так, как он вернулся с сервера firebase.   -  person teradyl    schedule 13.07.2017


Ответы (4)


Когда вы вызываете snapshot.val(), вы возвращаете объект JSON. Порядок ключей в объекте JSON определяется вашим браузером, а не Firebase.

Чтобы привести детей в порядок, используйте встроенный forEach метод снимка:

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() не является асинхронным вызовом.

person Frank van Puffelen    schedule 24.11.2015
comment
Поэтому, если нам нужны отсортированные данные, мы должны создать новый объект с новыми ключами или поместить каждый child.val () в массив. Разве это не ужасно неэффективно? - person Pier; 17.06.2016
comment
Не могли бы вы ответить на вопрос @Pier? У меня такой же вопрос. - person Onichan; 20.07.2016
comment
@Pier В этом нет необходимости, если вы используете другие типы событий, подробности см. В моем ответе. - person user2875289; 08.12.2016
comment
@Onichan Пожалуйста, посмотрите мой ответ. - person user2875289; 08.12.2016
comment
Я чувствую, что им нужно добавить это предостережение в официальные документы, потому что тот факт, что у меня был правильно написан запрос, никаких ошибок, но все же получение данных в том порядке, в котором они находятся в базе данных, озадачил меня, пока я не наткнулся на этот ответ. - person Hayko Koryun; 30.03.2017
comment
Вы имеете в виду, как пример в документации здесь? firebase.google.com/docs/database/web/ - person Frank van Puffelen; 31.03.2017
comment
вау, я использовал orderByChild в 21 месте в моем проекте в течение последних 2 лет и просто понял, что делаю это неправильно ... (после того, как пользователь сообщил об ошибке и после дальнейших поисков). Похоже, мне пора создать оболочку вроде getOrderedResults (снимок) {var obj = {} snapshot.forEach (function (child) {obj [child.key] = child.val ()}); return obj} - person vir us; 26.07.2019
comment
Я столкнулся с той же проблемой / решением в моей реализации Unity / C #: нужно повторять args.Snapshot.Children, чтобы получить упорядоченные значения, а не args.Snapshot.GetValue - person cjcurrie; 25.04.2021

Я знаю, что на этот вопрос был дан ответ, и ему больше 1 года, но, поскольку в разделе комментариев все еще есть некоторая путаница, я хотел бы добавить некоторую информацию.

Эта проблема

Исходная проблема заключается в том, что OP хочет получить упорядоченный список на основе дочернего ключа из базы данных Firebase в реальном времени, но .orderByChild('arg') не работает должным образом.

Но то, что не сработало, как ожидалось, - это не .orderByChild('arg'), а .on("value", callback). Потому что .on("value", callback) работает немного иначе, чем другие типы событий, такие как .on("child_added", callback).

Пример

Скажем, у нас есть база данных в реальном времени 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
}

введите описание изображения здесь

--

Если мы используем .on("child_added", callback), callback () будет вызываться 3 раза, каждый раз возвращает объект, и они возвращаются по порядку.

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

введите описание изображения здесь

Заключение

Если вам нужно получить только упорядоченные данные из firebase (например, для инициализации пользовательского интерфейса). Тогда ref.orderByChild('arg').once("child_added", callback) вам подходит, он прост и удобен в использовании.

Однако, если по какой-то причине вам нужно использовать ref.orderByChild('arg').on("value", callback), см. Ответ Фрэнка ван Пуффелена.

Ссылка

Прочтите документ Firebase для получения дополнительной информации о on(eventType, callback, cancelCallbackOrContext, context), их аргументы и их возвращаемые значения.

Еще один полезный документ: Работа со списками данных в Интернете

person user2875289    schedule 08.12.2016
comment
Настоящая причина, по которой вы видите разницу, заключается в том, что тип результата запроса FIB - это «словарь», где «ключ» (id) записи является «ключом» словаря. Следовательно, JS (браузер) сортирует этот список по ключу. Вот почему, если вы запрашиваете как «child_added» (один за другим) или используете «snapshot.forEach», вы можете обойти это явление. Так что это больше связано с JS, чем с FIB. Ответ @ frank-van-puffelen более правильный по этой причине. - person Elya Livshitz; 13.12.2017
comment
@ user2875289 Я использую nativescript + angular, и при использовании решения Фрэнка возникает ошибка. TypeError: snapshot.forEach is not a function - person Robert Williams; 24.06.2018

Для заказа с использованием прослушивателя событий 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

person Renan Coelho    schedule 30.05.2018
comment
Спасибо, искал child.key. : D - person Ravi Dhoriya ツ; 25.11.2019

Я боролся с той же проблемой в 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;      
     } 
}];
person Muhammed Tanriverdi    schedule 11.07.2017