为什么 Firebase 查询 [ ] 尽管 async/await?

Why is Firebase Query [ ] despite async/await?

我仍在努力理解如何从 Firestore 查询中提取值并将它们放入全局变量中。我(现在)明白异步性质意味着代码不会按照编写的顺序执行。但是,尽管 async 函数中有 await 关键字,但为什么 user 在以下代码块中仍然未定义?我理解(基于 ​​await 应该只应用到 get(),否则可能没有要迭代的值。

我的问题类似于this, but I run into the same issue as the comment and it looks like the question was never marked as answered. It is also similar to this,但是将所有内容推送到一个Promise,然后解决该promise 仍然没有将数据分配给变量。它只是打印了一个空数组。

我可以打印变量,所以我想我的问题是关于赋值的。此函数是 DialogFlowIntent 的处理程序。我强烈希望在调用数据库之外获得数据。在调用 firestore 时添加到代理响应并不总是将文本添加到代理,所以我想避免这种情况。

async function loginHandler(agent){     
     username = agent.parameters.username.name;      
     password = agent.parameters.password;

        const user = await db.collection("users")
                    .where("name","==",username)
                     .where("password","==",password)
                     .limit(1)
                     .get()
                     .then(querySnapshot =>{
                        querySnapshot.forEach(docSnapShot =>{
                            return docSnapShot.data();
                            //console.log.(docSnapShot.data()); //prints correct contents, so error is in programming logic
                            agent.add("Response"); // Would prefer to avoid this, but could refactor if I am fundamentally misunderstanding how to access Firebase data
                        })
                     })
                     .catch(error => console.log);
                                 

        console.log(user);      
       console.log("bort");  
}

用于证明确实存在正确数据的 Firestore 图片:

你检查过正确答案是什么了吗?

请说明您是指标题中的undefined,还是文中所说的empty array

我认为你的代码是正确的。我不希望 console.log(user) 的输出是 undefined。但是,空列表 [ ] 将是一个完全合理的答案。

也许 collection 中没有人使用该用户名和密码?

您是否尝试过删除用户名和密码相等的条件?如果 collection 不完全为空,那应该会给你一个元素。

forEach 迭代结果但不 return 任何东西,所以你的 return 里面没有做你期望的事情(forEach returns void 所以你正在 return 快照到一个正在 returning void 的函数。您可以创建一个局部变量来保存您迭代的结果,然后 return 那:

const user = await db.collection("users")
                    .where("name","==",username)
                    .where("password","==",password)
                    .limit(1)
                    .get()
                    .then(querySnapshot =>{
                        // Set up an empty array to return later
                        let data = []
                        querySnapshot.forEach(docSnapShot =>{
                            // Add each snapshot's data object to the array
                            data = [...data, ...docSnapShot.data()]
                        })
                        // Return `data` which will populate `user`
                        return data
                     })
                     .catch(error => console.log);

您或许可以拆分代码。 Return 首先从数据库中获取数据,然后 map 遍历数据以提取详细信息,然后 然后 将该结果分配给 user 变量。

async function loginHandler(agent) {

  username = agent.parameters.username.name;
  password = agent.parameters.password;

  // `await` the promise and assign it to
  // `querySnapshot`
  const querySnapshot = await db.collection('users')
    .where('name', '==', username)
    .where('password', '==', password)
    .limit(1)
    .get()
    .catch(error => console.log);
  
  const user = querySnapshot.docs.map(docSnapShot => {
    agent.add('Response');
    return docSnapShot.data();
  });

  console.log(user);

}