【问题标题】:ForEach only looping through first item on DataSnapshotForEach 仅循环遍历 DataSnapshot 上的第一项
【发布时间】:2020-04-04 23:56:40
【问题描述】:

我正在尝试遍历 DataSnapshot 的内容,然后根据条件为每个元素做一些工作,但目前,ForEach 只在第一项中工作。 “serverStatus”有时正在等待,有时在“onCall”中。当第一个项目是“onCall”时,不会像我认为应该做的那样遍历其余项目。下面是我从哪里获取信息的快照:

这是我的功能:

exports.manageCallRequests = functions.database.ref('/resquests/{userId}').onCreate((snap, context) => {
    const event = snap.val();

    console.log("function manageCallRequests is being called")
    var rootPath = admin.database().ref();
    var userOnCall = context.params.userId;

    var serversRef = rootPath.child('servers');
     var callRequest = event;
     var userTime = callRequest["time"];
     var waiting= "waiting";

  //We first get all the servers in ascending order depending on the last time they were used
  var serversSorted = serversRef.orderByChild('lastTimeUsed')


       //Gets the children on the "serversSorted" Query
       return serversSorted.once("value").then(allServers =>{
        //Checks if there is any child
            if(allServers.hasChildren()){



                    allServers.forEach(async function(server) {


                        //we extract the value from the server variable, this contains all the information 
                        //about each one of the servers we have
                        var serverInfo = server.val();
                        var serverKey = server.key;
                        var serverNumber = serverInfo["serverNumber"];
                        var serverStatus = serverInfo["serverStatus"];

console.log("server status "+serverStatus)
                        if(serverStatus === waiting){

                            const setCallRequest = await serversRef.child(serverKey).child("current").child("callRequest").set(callRequest);
                            const removeUserOnCall = await rootPath.child("resquests").child(userOnCall).remove();
                            const setServerStatus = await serversRef.child(serverKey).child("serverStatus").set("onCall");

                        }

                    });
                }else{
                    console.log("No servers available")


                }
            });

});

【问题讨论】:

  • 您如何观察这种行为?你在记录什么吗?你能显示它的输出并将其与你的期望进行比较吗?
  • 很可能与 Promises 无关,更可能的是 serverStatus === waiting 除了第一次迭代之外的所有内容都为 false
  • 这就引出了一个问题:上面代码中waiting 的值是多少?它是如何在 Cloud Functions 中调用的?我们在这里遗漏了一些必要的信息,这些信息对于提供帮助是必要的。另见how to create a minimal, complete, verifiable example
  • 我已经编辑了我的问题。即使 serverStatus === waiting 为 true,该函数也具有相同的行为

标签: javascript node.js firebase-realtime-database google-cloud-functions


【解决方案1】:

我有相同的行为,因为我的云函数在所有迭代都在 forEach 循环中执行之前退出。我使用这个 sn-p 代码摆脱它:

for (const doc of querySnapshot.docs) {
    // Do wathever you want    
    // for instance:
    await doc.ref.update(newData);
}

【讨论】:

【解决方案2】:

我找到了两种方法来完成这项工作。如果我们有一个没有任何 OrderBy* 调用的 DataSnapshot,第一个很有用,在这种情况下,将是:

var allServers = await serversRef.once("value");

for (let serverKey of Object.keys(allServers.val())){
   var server = allServers[serverKey];
    //Do some work
}

我们需要首先获取对象的键,然后才能从 for 循环中提取它,正如 here 所解释的那样,否则我们将得到“TypeError: 'x' is not iterable”

现在这个特殊情况的问题是,a 有一个 DataSnapshot,它之前在 var serversSorted = serversRef.orderByChild('lastTimeUsed') 排序,所以当我们调用 Object.keys(allServers.val()) 时,返回的值不再排序,这就是 forEach() 派上用场的地方。它保证 DataSnapshot 的子项将按照 here 解释的查询顺序进行迭代,但是由于某些原因,在 forEach 循环中执行一些异步工作时,这似乎不起作用,这就是我必须这样做的原因:

var serversSorted = serversRef.orderByChild('lastTimeUsed')
    var allServers = await serversSorted.once("value");

    //Checks if there is any children
    if (allServers.hasChildren()) {
        //if there is iterate through the event that was passed in containing all
        // the servers
        var alreadyOnCall = false;
        var arrayOfServers = []
        var arrayOfKeys = []

        allServers.forEach(function(individualServer){
                arrayOfKeys.push(individualServer.key)
                arrayOfServers.push(individualServer)
        })

        for (var serveIndex = 0; serveIndex < arrayOfServers.length;serveIndex++){

            var serverObj = arrayOfServers[serveIndex]
            var serverObject = serverObj.val()
            var serverKey = arrayOfKeys[serveIndex]

            var serverStatus = serverObject["serverStatus"]; 
            var serverNumber = serverObject["serverNumber"]; 

            console.log("server info "+serverStatus+" "+serverKey);

            if (serverStatus === waiting && alreadyOnCall === false) {
                const setCallRequest = await serversRef.child(serverKey).child("current").child("callRequest").set(callRequest);
                const removeUserOnCall = await rootPath.child("resquests").child(userOnCall).remove();
                const setServerStatus = await serversRef.child(serverKey).child("serverStatus").set("onCall");
                alreadyOnCall= true
                console.log("Call properly set");
            } 
        }


    }

【讨论】:

    猜你喜欢
    • 2018-06-26
    • 1970-01-01
    • 2013-09-17
    • 2013-12-16
    • 2017-09-10
    • 2013-12-26
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    相关资源
    最近更新 更多