如何遍历Firebase Firestore文档数组并将值推入数组?

3
我正在使用node.JS编写Firebase云函数,从Firebase Firestore中读取用户数据。我无法将token值推入token数组,并在函数结束时返回所有令牌。我的代码如下:

function getTokens(subscribers) {
    return new Promise(async function (resolve, reject) {
        const tokenArray = [];
        subscribers.forEach(async (subscriber) => {
            await firestore
                .collection('users')
                .doc(subscriber)
                .get()
                .then((user) => {
                    console.log("Getting user data for user: ", user);
                    const tokens = user.data().tokens;
                    if (tokens) {
                        tokens.forEach((token) => {
                            console.log("Adding token to token array"); // data is available here but does not push into tokenArray
                            tokenArray.push(token);
                        });
                    }
                }).catch((error) => { console.error(error); reject(error); });
        });
        console.log("Token Array -- Final: ", tokenArray);
        resolve(tokenArray);
    });
};

2个回答

3

OP代码可以通过以下方式进行更正和简洁:

async function getTokens(subscribers) {
  const getUser = subscriber => firestore.collection('users').doc(subscriber).get();
  const promises = subscribers.map(getUser);
  const users = await Promise.all(promises);
  return users.map(user => user.data().tokens).flat()
}

一些注释:

  • 将函数标记为async,因为它包含了一个await
  • 不要使用Promise.new()创建额外的promise,Firestore的get()返回一个promise
  • mapget promises收集到一个数组中,并使用Promise.all()运行它们
  • 映射结果用户的data.tokens会产生一个数组的数组。将其展平即可完成。
  • 仅抛出异常的catch与没有catch一样

我喜欢使用 .map() 和 .flat() 的组合。很棒! - LeadDreamer

2

forEach 循环中无法使用 async-await。请尝试映射一个 Promise 数组,然后像下面展示的那样使用 Promise.all()

function getTokens(subscribers) {
  return new Promise(async function (resolve, reject) {
    
    const subscribersDocs = await Promise.all(
      subscribers.map((subscriber) => {
        return firestore.collection("users").doc(subscriber).get();
      })
    );


    const tokenArray = subscribersDocs.reduce((acc, curr) => {
      const tokens = curr.data().tokens;
      if (tokens) {
        acc = acc.concat(tokens);
      }
      return acc;
    }, []);

    console.log("Token Array -- Final: ", tokenArray);
    resolve(tokenArray);
  });
}

还有一个值得注意的地方:在forEach循环中使用async/await


2
几个性能要点:如果你的subscribers在开始时不是完全随意的列表,最好使用查询来选择它们。读取成本相同,但只需要一次往返。同样地,与其循环遍历tokens并使用push(),你应该能够使用.concat() - LeadDreamer
1
谢谢@LeadDreamer。我应该提到in运算符,但它只在数组最多有10个元素时才有用。 - Dharmaraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接