2015-11-24 6 views
15

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

Можете ли вы показать свои данные неупорядоченными, а затем, как это выглядит, когда оно возвращается в качестве моментального снимка? –

+0

Обновлен вопрос с моментальным снимком – JohnAndrews

+1

Трудно сказать, что происходит с данными, которые вы предоставили. Можете ли вы создать JSBin, демонстрирующий вашу проблему? Это облегчило бы устранение неполадок, что происходит. –

ответ

54

Когда вы звоните 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() не асинхронный вызов.

+13

Итак, если нам нужны отсортированные данные, мы должны создать новый объект с новыми ключами или поместить каждый child.val() в массив. Разве это не ужасно неэффективно? – Pier

+4

Не могли бы вы ответить на вопрос @Pier? У меня такой же вопрос. – Onichan

+1

@Pier Вам не нужно, если вы используете другие eventTypes, см. Мой ответ для подробностей. – user2875289

11

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

Проблема

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

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

Пример

Скажем, у нас есть firebase базу данных в режиме реального времени, как показано ниже:

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

-

Если мы используем .on("value", callback), обратный вызов() будет вызываться один раз, и возвращать Объектный массив из 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), обратный вызов() будет вызываться в 3 раза, каждый раз возвращает объект, и они возвращаются в порядке.

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 (например, инициализировать интерфейс.) Затем ref.orderByChild('arg').once("child_added", callback) подходит вам хорошо, это простой и легкий в использовании.

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

Ссылка

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

Другого полезный документ: Work with Lists of Data on the Web

+1

Настоящая причина, по которой вы видите разницу, в том, что тип результата запроса FIB - это «словарь», где «ключ» (идентификатор) записи является «ключом» словаря. Следовательно, JS (браузер) сортирует этот список по его ключу. Вот почему, если u запрашивает как «child_added» (один за другим) или использует «snapshot.forEach», вы обойдете это явление. Так что это скорее вещь JS, чем вещь FIB. @ Ответ frank-van-puffelen более правильный по этой причине. –

+0

@EliLivshitz Полностью согласен. – user2875289

0

я боролся с той же проблемой в прошивке. Если вы конвертируете моментальный снимок в объект 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;  
    } 
}]; 
Смежные вопросы