Firebase 云函数在 return 之前结束

Firebase cloud function ends before return

我制作了一个 SwiftUI 应用程序,它通过多个 Firebase 云函数获取其 Firestore 数据。我要获取的 Firestore 文档的结构如下:

Firestore structure

现在,我想调用一个名为“getLocationObjectsFromUser”的云函数,它从用户相关集合 locationIds 中获取所有 LocationIds。然后,我想从具有特定 locationId 的位置文档中获取所有数据,包括集合“UserIds”。

我试过类似的方法,但在这种情况下,firebase 函数日志总是告诉我函数已经完成,尽管它还没有完成获取所有数据。因此,我的 swift 应用程序没有获取任何数据。我如何才能 return 我想要的所有数据?

函数代码:

exports.getLocationObjectsFromUser =
    functions.https.onCall((data, context) => {
      const locations = [];
      let userIds = [];

      return userRef
          .doc(data.userId)
          .collection("locationIds")
          .where("status", "==", true)
          .get()
          .then((querySnapshot) => {
            querySnapshot.forEach((doc) => {
              return locationRef
                  .doc(doc.id)
                  .get()
                  .then((locationDoc) => {
                    return locationRef
                        .doc(locationDoc.id)
                        .collection("userIds")
                        .get()
                        .then((querySnapshot1) => {
                          querySnapshot1.forEach((doc1) => {
                            userIds.push(doc1.id);
                          });
                          const object = {...locationDoc.data(), userIds};
                          locations.push(object);
                          userIds = [];

                          // if statement to avoid return before function has finished running
                          if (querySnapshot.size == locations.length) {
                            return {locations: locations};
                          }
                        });
                  });
            });
          });
});

Swift代码:

func getLocationObjectsFromUser(_ user_id: String, onSuccess: @escaping ([LocationModel]) -> Void, onError: @escaping(_ error: String?) -> Void) {

        let dic = ["userId" : user_id] as [String : Any]
        
        self.functions.httpsCallable("getLocationObjectsFromUser").call(dic) { (result, error) in
            if let error = error as NSError? {
                print("ERROR")
                print(error)
                onError(error.localizedDescription)
            }
            if let data = result?.data as? [String: Any] {
                print("DATA")
                print(data)
 
                // Later on i want to return the LocationModel with something like this: onSuccess(Data).
            }
            // i do not get any data after calling the function.
        }
    }

问题是这里的最后一行:

return userRef
    .doc(data.userId)
    .collection("locationIds")
    .where("status", "==", true)
    .get()
    .then((querySnapshot) => {
      querySnapshot.forEach((doc) => {
        return locationRef...

由于您要遍历 querySnapshot 中的文档,因此您在其中有多个调用 return locationRef...,并且您没有代码来确保所有这些读取在 Cloud Function已终止。

每当您需要在代码中的同一级别等待多个操作时,您的答案就是使用 Promise.all:

return userRef
    .doc(data.userId)
    .collection("locationIds")
    .where("status", "==", true)
    .get()
    .then((querySnapshot) => {
      return Promise.all(querySnapshot.docs.map((doc) => {
        return locationRef...

所以变化:

  • 我们 return 一个 Promise.all() 只有在所有嵌套读取完成后才解析。

  • 我们使用 querySnapshot.docs.map 而不是 querySnapshot.forEach,这样我们就可以得到一组要传递给 Promise.all 的承诺。