orderByChild 在 Firebase 中不起作用

Posted

技术标签:

【中文标题】orderByChild 在 Firebase 中不起作用【英文标题】:orderByChild not working in Firebase 【发布时间】:2016-02-26 21:45:24 【问题描述】:

我正在尝试查询我的数据库,以便它根据子键检索有序列表。我按如下方式进行操作(见下文),但没有任何反应,这意味着它返回的对象排序方式与存储在 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"

【问题讨论】:

您能否将您的数据显示为无序,然后作为快照返回时的样子? 用快照更新了问题 很难判断您提供的数据发生了什么。你能创建一个 JSBin 来演示你的问题吗?这样可以更轻松地解决正在发生的事情。 以下可能的答案。但正如大卫所说:下次考虑创建一个 JSBin/JsFiddle,因为它将提供一个最小的、完整的示例。现在缺少的一件事是足够的数据来了解您所看到的内容以及可能的原因(“最小”和“完整”之间总是很棘手的平衡)。 确保您实际上是在循环通过快照子项。如果您只是打印快照,它会像标准 JSON 一样排序,而不是从 firebase 服务器返回的方式。 【参考方案1】:

当您调用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() 不是异步调用。

【讨论】:

因此,如果我们需要对数据进行排序,我们必须使用新键创建一个新对象,或者将每个 child.val() 放入一个数组中。这不是非常低效吗? 您介意回答@Pier 的问题吗?我有同样的问题。 @Onichan 请看我的回答。 我觉得他们需要将此警告添加到官方文档中,因为我正确编写了查询,没有错误,但仍然按照数据库中的顺序获取数据,这让我很难过直到我遇到这个答案。 您的意思是像此处文档中的示例? firebase.google.com/docs/database/web/…【参考方案2】:

我知道这个问题已经回答了并且已经超过 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个对象的Object Array。

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 Document,了解有关on(eventType, callback, cancelCallbackOrContext, context)、它们的参数和返回值的更多信息。

另一个有用的文档:Work with Lists of Data on the Web

【讨论】:

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

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

【讨论】:

【参考方案4】:

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

以上是关于orderByChild 在 Firebase 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

具有两次 orderByChild 条件的 Firebase 查询 [重复]

Flutter:Firebase 实时数据库 orderByChild 对查询结果没有影响

firebase 查询 orderByChild().equalTo() android kotlin 的问题

Firebase .orderByChild().equalTo().once().then() 当孩子不存在时承诺

firebase 和 Ionic 2 上的降序 orderByChild()

这个 orderByChild Firebase 实时代码有啥问题?