Firebase 嵌套查询

Firebase Nested Query

我是 firebase 的新手并且已经通读了文档,但似乎无法找到一个方法来获取所有填充了用户数据的阶梯的列表。我真的不想在他们所属的每个阶梯中复制用户数据。

这是我的数据结构:

{
"ladders" : [ {
    "description" : "Real Real Tennis",
    "name" : "Ping Pong",
    "players" : {
      "simplelogin:5" : true
    }
  }, {
    "description" : "Real Tennis",
    "name" : "Mario Tennis",
    "players" : {
      "simplelogin:5" : true
    }
  } ],
  "users" : {
    "simplelogin:5" : {
      "email" : "bob@bob.com",
      "md5hash" : "1e737a7b6e1f0afb1d6fef521097400b",
      "name" : "Bob",
      "username" : "bob1"
    }
  }
}

这是我最好的尝试,但看起来梯子查找已经完成,returns 在用户查找完成之前,所以 returns 玩家是空的。

laddersRef.on('value', function(laddersSnapShot){
        var ladders = []
        laddersSnapShot.forEach(function(ladderData) {
            var ladder = ladderData.val();
            ladder.players = [];
            ladder.id = ladderData.key();

            laddersRef.child(ladder.id).child('players').on('value', function(snap){
                snap.forEach(function(player){
                    usersRef.child(player.key()).on('value', function(snap1){
                        ladder.players.push(snap1.val())
                    })
                })
            })
            ladders.push(ladder)
        });
    });

关于此示例的大部分内容都已损坏。在以有意义的方式回答这个问题之前,通读 the guide 是必不可少的。如所写,您的代码会在任何时候在梯子中的任何地方的任何字段/被修改时在每个梯子的玩家列表上建立一个新的侦听器。

发生这种情况是因为 laddersRef.on('value') 将在该路径中的任何位置发生更改时随时更新。每次发生这种情况时,您都会建立 laddersRef.child(ladder.id).child('players').on('value'),这会在每个阶梯的玩家/路径上创建多个侦听器。 retrieving data

中介绍了其基本原理

这里的正确答案是按预期使用这些工具,而不是试图通过异步 API 方法进行缓慢、乏味、容易出错的同步过程。

要直接回答你的问题,这就是你要求的:

function done(ladders) {
   console.log(ladders);
}

laddersRef.on('value', function(laddersSnapShot){
  function doneWithLadder() {
     if( ++laddersDone === laddersNeeded ) {
       done(ladders);
     }
  }

  var ladders = [];
  var laddersDone = 0;
  var laddersNeeded = laddersSnapShot.numChildren();

  laddersSnapShot.forEach(function(ladderData) {
    var ladder = ladderData.val();
    var playersFound = 0;
    var playersNeeded = ladderData.numChildren();
    ladder.players = [];
    ladder.id = ladderData.key();
    laddersSnapshot.child('players').forEach(function(ps) {
       usersRef.child(ps.key()).once('value', function(userSnap) {
           ladder.players.push(usersSnap.val());
           if( ++playersFound === playersNeeded ) {
              doneWithLadder();
           }
       });
    });
  });
});

但这更优雅(更优雅的是使用框架并完全避免这种情况):

function addLadder(snap) {
   putLadderInDom(snap.key(), snap.val());
   snap.ref().child('players').on('value', changePlayers);
   // Use whatever framework you have available to put this into
   // the DOM. Be sure to keep the record key around so you can
   // add the user in later
}

function changePlayers(playersSnap) {
   var ladderKey = playersSnap.parent().key();
   var numFetched = 0;
   var numPlayersToFetch = playersSnap.numChildren();
   var profiles = {};
   playersSnap.forEach(function(ss) {
      loadProfile(ss.key(), function(userSnap) {
         profiles[userSnap.key()] = userSnap.val();
         if( ++numFetched === numPlayersToFetch ) {
            updatePlayers(ladderKey, profiles);
         }
      });
   });
}

function updatePlayers(ladderKey, profiles) {
   // use whatever framework you have available to insert profiles
   // into the DOM
}

function loadProfile(key, callback) {
   usersRef.child(key).once('value', callback);
}

laddersRef.on('child_added', addLadder);