orderByChild 在 Firebase 中不起作用

IT技术 javascript firebase firebase-realtime-database
2021-03-14 22:20:15

我正在尝试查询我的数据库,以便它检索基于子键的有序列表。我按如下方式执行(见下文),但没有任何react,这意味着它返回的对象与存储在 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"
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()不是异步调用。

你介意回答@Pier 的问题吗?我也有同样的问题。
2021-04-26 22:20:15
我觉得他们需要将这个警告添加到官方文档中,因为我正确写出了查询,没有错误,但仍然按照数据库中的顺序获取数据这一事实让我感到困惑,直到我遇到了这个答案。
2021-04-26 22:20:15
你的意思是像这里文档中的例子?firebase.google.com/docs/database/web/...
2021-05-03 22:20:15
@Onichan 请看我的回答。
2021-05-15 22:20:15
因此,如果我们需要对数据进行排序,我们必须使用新键创建一个新对象或将每个 child.val() 放入数组中。这不是非常低效吗?
2021-05-20 22:20:15

我知道这个问题已经有人回答了,而且已经有1年多了,但是由于评论区还有一些混乱,我想补充一些信息。

问题

最初的问题是 OP 想要根据 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),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次,每次都返回一个Object,并且依次返回

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

在此处输入图片说明

结论

如果您只需要从 firebase 获取有序数据(例如初始化 UI)。那么非常ref.orderByChild('arg').once("child_added", callback)适合您,它简单易用。

但是,如果出于某种原因您需要使用ref.orderByChild('arg').on("value", callback),请参阅 Frank van Puffelen 的回答。

参考

请阅读Firebase 文档以获取有关on(eventType, callback, cancelCallbackOrContext, context)、它们的参数和返回值的更多信息

另一个有用的文档:使用 Web 上的数据列表

@user2875289 我正在使用 nativescript+angular,当我使用 Frank 的解决方案时,它给了我错误。 TypeError: snapshot.forEach is not a function
2021-05-07 22:20:15
您看到差异的真正原因是 FIB 查询结果的类型是“字典”,其中记录的“键”(id) 是字典的“键”。因此,JS(浏览器)按其键对该列表进行排序。这就是为什么如果您查询为“child_ added”(一个接一个)或使用“snapshot.forEach”,您将解决此现象。所以这更多是 JS 的事情而不是 FIB 的事情。出于这个原因,@frank-van-puffelen 的回答更正确。
2021-05-13 22:20:15

使用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

谢谢,我正在寻找child.key:D
2021-05-02 22:20:15

我在 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;      
     } 
}];