【问题标题】:In Firebase, how can I query the most recent 10 child nodes?在 Firebase 中,如何查询最近的 10 个子节点?
【发布时间】:2016-08-04 00:30:13
【问题描述】:

我正在使用childByAutoId() 来生成我的孩子。每个孩子的样子:

{
    user_id: 1
}

我想获取最近添加的最后 10 个,按时间 DESC 排序。最简单的方法是什么?

【问题讨论】:

  • 同步一个位置上最近的 10 个孩子是 ref.queryOrderedByKey().queryLimitedToLast(10)。但这可能意味着我误解了你的问题。您能否详细说明您的数据是什么样的(JSON 为文本,请不要截图),您的代码是什么样的以及存在什么问题?
  • 您是否对所有答案投了反对票?如果是这样,您能否对每个答案发表评论,说明为什么它没有帮助?在我之前的评论中回答这个问题也将大大有助于我们为您提供帮助。例如,您的伪 json 中没有时间戳/时间。

标签: ios firebase


【解决方案1】:

答案是您需要使用一些逆向逻辑,并在每个节点内存储一个时间戳键:值对作为负值。我省略了 user_id: 1 以保持答案更清晰。

这是 Firebase 结构

"test" : {
    "-KFUR91fso4dEKnm3RIF" : {
      "timestamp" : -1.46081635550362E12
    },
    "-KFUR9YH5QSCTRWEzZLr" : {
      "timestamp" : -1.460816357590991E12
    },
    "-KFURA4H60DbQ1MbrFC1" : {
      "timestamp" : -1.460816359767055E12
    },
    "-KFURAh15i-sWD47RFka" : {
      "timestamp" : -1.460816362311195E12
    },
    "-KFURBHuE7Z5ZvkY9mlS" : {
      "timestamp" : -1.460816364735218E12
    }
  }

这就是将其写入 Firebase 的方式;我只是用一个 IBAction 作为一个按钮来写出几个节点:

let testRef = self.myRootRef.childByAppendingPath("test")

let keyRef = testRef.childByAutoId()

let nodeRef = keyRef.childByAppendingPath("timestamp")

let t1 = Timestamp

nodeRef.setValue( 0 - t1) //note the negative value

以及读取它的代码

    let ref = self.myRootRef.childByAppendingPath("test")
    ref.queryOrderedByChild("timestamp").queryLimitedToFirst(3).observeEventType(.ChildAdded, withBlock: { snapshot in
        print("The key: \(snapshot.key)") //the key
    })

我声明了一个小函数来返回当前时间戳

var Timestamp: NSTimeInterval {
    return NSDate().timeIntervalSince1970 * 1000
}

和输出

The key: -KFURBHuE7Z5ZvkY9mlS
The key: -KFURAh15i-sWD47RFka
The key: -KFURA4H60DbQ1MbrFC1

如您所见,它们的顺序相反。

注意事项:

  1. 将时间戳记为负值
  2. 读取时使用 .queryLimitedToFirst 而不是 last。

注意,您也可以像往常一样读取数据并将其添加到数组中,然后对数组进行降序排序。这会使客户端付出更多的努力,如果您有 10,000 个节点,则可能不是一个好的解决方案。

【讨论】:

  • 如何将FIRServerValue.timestamp() 存储为负值?我不能只做0 - FIRServerValue.timestamp(),因为timestamp()[AnyHashable: Any] 对象...任何帮助将不胜感激。
  • @MoreCode 如果您查看问题和答案,则会在客户端应用程序中生成时间戳,而不依赖于 FIRServerValue.timestamp()。请发布一个单独的问题,因为它是一个涉及服务器时间戳值的不同答案。发布,我会发布解决方案!
  • 当您有 100K 个项目时,queryOrderedByChild("timestamp") 会变慢吗?假设它们是反向存储的,每次都需要反向排序?
  • @MuhammadHassan 不确定我是否理解这个问题。如果您按照我的答案存储时间戳,它们将以相反的顺序(降序)存储,因此每次都不需要反转它们。我最后的评论指出,作为替代方案,读入所有节点并在代码中排序 - 但这可能对大量节点不利。然而,最重要的是,如果您需要一次读取 10 万个项目,那么可能有一种更好的方法来构建数据!
  • @Jay 我的理解是,项目是按照你写它们的顺序存储的,所以除非你按顺序插入它们,否则它们不会按顺序存储。您的代码使用在服务器中执行的 queryOrderedByChild("timestamp").queryLimitedToFirst(3) 并且它不知道它们是如何排序的,因此它每次都会对它们进行排序并获得前 3 个。所以假设我想得到最后一个。我认为它会随着你的成长而变慢,除非你把 indexOn(timestamp)
【解决方案2】:

我假设您的数据实际上如下所示:

someDataSet: {
    longUID-1: {
        timeCreated: 9999999999, // (seconds since the javascript epoch)
        user_id: 1
    },
    longUID-2: {
        timeCreated: 1111111111,
        user_id: 2
    },
    longUID-3: {
        timeCreated: 3141592653,
        user_id: 3
    }
}

您可以通过在 for 循环或任何其他方法中多次调用 Firebase.push({user_id: ###, timeCreated: ###}) 来自动执行此操作。也许您正在向网页添加新闻报道,但您只想让您的用户看到最新的报道——IDK。但您的问题的答案是使用 Firebase 的 ref.orderByChild()ref.limitToLast()

var ref = new Firebase("<YOUR-FIREBASE-URL>.firebaseio.com/someDataSet"); 
    //the "/someDataSet" comes from the arbitrary name that I used up above

var sortedRef = ref.orderByChild('timeCreated');
    //sort them by timeCreated, ascending

sortedRef.limitToLast(2).on("child_added", function(snapshot){
    var data = snapshot.val();

    console.log(data);

    /* do something else with the data */
});

//The console would look like this

// Object {timeCreated: 9999999999, user_id: 1}
// Object {timeCreated: 3141592653, user_id: 3}

之所以发生这种情况,是因为程序首先将具有最大 timeCreated 值的孩子放在首位,然后将第二大(值)放在第二位...... 另请注意,当您按子项对它们进行排序时,longUID 没有任何意义,其他值(在这种情况下为 user_id)也没有意义

这里是文档:

【讨论】:

  • 好答案,但 OP 想要降序,而不是升序。
  • 此外,ref.orderByChild('timeCreated') 和其他一些代码一样不是有效代码。这是一个 iOS 问题。
  • @jay 我对它们进行了升序排序,但随后采用了 LAST 几个元素。根据定义,这意味着我拥有价值最高的元素......
  • @jay 你是对的,但是我为浏览器编写了我的代码——我一直在使用的平台。
【解决方案3】:

代码:ref.queryOrderedByKey().queryLimitedToLast(10) 可用于获取最近的 10 条数据。但是,默认情况下这是一个升序。

或者,您可以通过

订购您的数据
ref.orderByChild("id").on("child_added", function(snapshot) {
  console.log(snapshot.key());
});

默认情况下,这也显示升序。将其更改为降序有点棘手。我建议将 id 乘以 -1 如下所示,然后对它们进行排序。

var ref= new Firebase("your data");
ref.once("value", function(allDataSnapshot) {
  allDataSnapshot.forEach(function(dataSnapshot) {
    var updatedkey = -1 * dataSnapshot.key();
    ref.update({ element: { id: updatedkey}});
  });
});

这两个 SO 页面也可能对您有用,请检查:

How to delete all but most recent X children in a Firebase node?

firebaseArray descending order?

【讨论】:

  • 这并不能真正回答问题。 OP 希望按降序返回 X 个子级。此答案中的代码按升序返回所有孩子 - 如果 iOS 设备上有 100,000 个孩子,这可能会超过内存,这可能是灾难性的。此外,这是一个 iOS 问题,因此应使用 Swift 或 ObjC 代码。您能否更新您的答案以解决问题?
  • 我没有得到你我的朋友。为什么在将 ids 乘以 -1 后 OP 不能使用“ref.queryOrderedByKey().queryLimitedToLast(10)”?
  • 答案中发布的代码读取节点 ref.once("value", function(allDataSnapshot) 的所有内容,然后乘以 -1。如果是 100,000 个节点,则可能是一个问题。跨度>
  • 在这种情况下,此代码将 100000 个节点乘以 -1(它们的 id),然后程序员将能够通过排序达到最近的 10 个值。然后用户应该通过再次乘以 -1 来更新数据。是的,我同意它可能会对性能产生负面影响,但这是提供 OP 要求的一种方式。我很乐意听到其他提供更好性能的替代方案..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2017-09-10
  • 1970-01-01
  • 2016-09-30
  • 2018-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多