【问题标题】:Firebase database sort by deeper childFirebase 数据库按更深的孩子排序
【发布时间】:2017-06-01 23:12:16
【问题描述】:

考虑 Firebase 数据库的以下结构:

    • 游戏1
      • $playerUidA
        • 得分:50
      • $playerUidB
        • 得分:10
      • .....
    • 游戏2
      • $playerUidC
        • 得分:20
      • $playerUidD
        • 得分:30
      • .....
    • 游戏3
      • .....

我想运行一个返回所有游戏节点的查询,其中每个游戏节点的子节点(玩家)将根据 score 进行排序。游戏节点包含每个玩家的UID,每个UID节点包含玩家的得分。我也在存储其他数据,但是,为了这个示例,我将只使用分数。

我可以用一个查询来做到这一点吗?就像是 rootRef.child("root").orderByChild("score")?不幸的是,这似乎不起作用。

或者实现这一点的唯一方法是在客户端手动排序项目?

@Puf - 希望你能回答这个问题:)

【问题讨论】:

    标签: firebase firebase-realtime-database


    【解决方案1】:

    虽然这个问题相当老了,但可能会有人(像我一样)绊倒它。特别是因为以与问题作者类似的方式构建数据库非常直观,例如为游戏创建(例如)排行榜系统。由于答案有点过时,我想添加一些东西。

    前段时间,开发者增加了由嵌套很深的孩子订购的可能性! (请参阅Ordering by a specified child key)为此,您基本上必须做与作者完全相同的事情,并另外使用@adolfosrs 给出的答案的第一部分。基本上你必须做两件事:

    1. 使用.indexOn(如@adolfosrs 所述)
    2. 使用OrderByChild() 命令。

    要在@steliosf 给出的示例上进行这项工作,您必须执行以下操作:

    首先在您的数据库规则中设置 .indexOn:

    {
      "rules": {
        "$gameId": {
          ".indexOn": "score",
          "$playerUid": {
            ...  
          }
        }
      }
    }
    

    第二使用问题作者已经使用的命令:

    rootRef.Child("root").OrderByChild("score")
    

    我建议您始终添加 LimitToFirst() 或 LimitToLast() 命令,以避免拉取可能包含大量数据的整个数据库(当然取决于数据库的大小)。例如,要获得您可以使用的前 10 名分数:

    rootRef.Child("root").OrderByChild("score").LimitToLast(10)
    

    由于数据是按升序排列的,所以需要使用 LimitToLast()。

    【讨论】:

      【解决方案2】:

      如果您希望所有游戏按玩家得分排序,您只需使用.indexOn 规则即可。

      {
        "rules": {
          "$gameId": {
            ".indexOn": "score",
            "$playerUid": {
              ...  
            }
          }
        }
      }
      

      这将使您的数据在数据库中保持排序,因此当您检索它时,您将准备好所有数据。但请记住,如果您想检索所有游戏和所有玩家,这意味着您将获取整个数据库。所以你应该看看你的应用程序的需求,也许重新考虑结构。

      在扩展时可能会有所帮助的是迭代游戏并使用 firebase.database().ref(gameId).limitToLast(10) 检索有限数量的用户。

      更新

      对于您的示例,您将拥有具有以下请求的所有游戏:

      firebase.database().ref().once('value', snap => {
          //prints all players for each game sorted ascending.
          snap.forEach(game => {
              game.forEach(player => {
                  console.log(player.val());
              });
          });
      });
      

      【讨论】:

      • 我在数据库规则中使用".indexOn": "score",我可以检索单个游戏节点,其中玩家按分数排序。问题是我无法检索 所有 游戏节点,其中每个游戏节点的子节点(玩家)都按分数排序。这不能通过单个查询来完成。我必须为每个游戏节点运行不同的查询,或者手动对客户端上的子节点进行排序。 PS。当然,我并不是要获取整个数据库,结构只是一个例子。
      • 嘿@MScott,它有用吗?如果您仍有任何疑问,请告诉我。
      • 感谢@adolfosrs 的建议。不幸的是,玩家没有通过游戏父节点上的单个查询进行排序。我最终在 for 循环中为每个游戏节点运行了一个查询,该循环有效,但这不是我想要的最佳解决方案。但似乎没有其他解决方案。要么是这个(多个查询),要么是在游戏父节点上运行一个查询并在客户端手动对每个游戏节点的子节点进行排序。
      猜你喜欢
      • 2021-08-15
      • 2020-05-04
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 2016-01-31
      • 2019-01-21
      • 2017-10-07
      相关资源
      最近更新 更多