扩展 Firebase Firestore 计划事件

Posted

技术标签:

【中文标题】扩展 Firebase Firestore 计划事件【英文标题】:Scaling firebase firestore scheduled event 【发布时间】:2019-09-24 16:23:08 【问题描述】:

我有一个每 4 小时运行一次的 pubsub 活动。我想在预定活动之后保存所有用户的团队。我是批量写入,但批量写入每次提交的写入限制为 500 次。下面是一个类似于我正在尝试做的示例代码。

问题:如何自动扩展批量写入。

exports.updateNews = functions.pubsub
  .topic("my-scheduled-topic")
  .onPublish(message => 
    return axios
      .get(
        "https://newsapi.org/v2/top-headlines?apiKey=someKey&sources=espn-cric-info"
      )
      .then(result => 
        const batch = db.batch();
        result.data.articles.forEach(article => 
          const docRef = db.collection("news").doc();
          batch.set(docRef, article);
        );
        return batch.commit();
      )
      .then(result => 
        console.log(result);
        return result;
      )
      .catch(error => 
        console.log(error);
        return error;
      );
  );

【问题讨论】:

【参考方案1】:

如果您的批次遇到 500 次写入的限制,您可以改用 Promise.all(),如下所示。当add() 方法调用返回的所有承诺都已解决时,它将返回一个解决的承诺。

exports.updateNews = functions.pubsub
  .topic("my-scheduled-topic")
  .onPublish(message => 
    return axios
      .get(
        "https://newsapi.org/v2/top-headlines?apiKey=someKey&sources=espn-cric-info"
      )
      .then(result => 
        const promises = [];
        result.data.articles.forEach(article => 
           promises.push(db.collection("news").add(article));
        );
        return Promise.all(promises);
      )
      .then(results => 
        console.log(results);
        return null;
      )
      .catch(error => 
        console.log(error);
        return null;
      );
  );

【讨论】:

Ty 再次我正在考虑对我昨天的问题发表评论。你能看看我发布的答案吗?代码正在运行,并且进行了多次批量写入,我只是不希望它失败。如果我能改进它,需要建议。 我对 Promise 还不满意,这就是为什么我试图避免它们的原因,我的 Linter 尖叫着说我不应该嵌套 Promise。 @Abdul-RafayShaikh 实际上,如果您使用 Firebase 异步任务,就无法避免承诺! :-) 我知道一开始可能有点“吓人”,但是如果你花时间研究 Promise,它们并没有那么复杂! :-) PS:我在建议的答案中添加了一些 cmets。我认为您应该尝试上述建议的答案。【参考方案2】:

我想我自己解决了需要专家意见:

我知道我的问题代码看起来不像我在提问之前简化了问题的答案。

\\\ reference the collection I wanted to save to or the place I wanna write
var userTeamsSave = db.collection("saveTeams");

\\\ api call
  db.collection("news")
    .get()
    .then(querySnapshot => 

     \\\ create Json array from query snapshot

      let users = [];
      querySnapshot.forEach(user => 
        users.push( id: user.id, data: user.data() );
      );

      return users;

    )
    .then(users => 

      var counter = 0;
      var commitCounter = 0;
      var batches = [];

      \\\ array of batches
      batches[commitCounter] = db.batch();
      users.forEach(user => 

      \\\ limit batch write in 1 commit upto 499
        if (counter <= 200) 

          var thisRef = userTeamsSave.doc(user.id);
          batches[commitCounter].set(thisRef, user.data);
          counter = counter + 1;

         else 
        \\\\ Reset Counter
          counter = 0;
          thisRef = userTeamsSave.doc(user.id);
          batches[commitCounter].set(thisRef, user.data);
          commitCounter = commitCounter + 1;
          batches[commitCounter] = db.batch();

        
      );

      \\\ return all batches
      return batches;
    )
    .then(fullBatch => 
      fullBatch.forEach(batch => 
        console.count("wrote batch");

       \\\ commit all batches
        return batch.commit();
      );
      return;
    )
    .catch(error => 
      console.error(error);
      return error;
    );

【讨论】:

要回复您的审查请求,恕我直言,我至少看到以下几点:对于 1/ 您需要返回对 db.collection("news").get() 的调用 2/ 您不需要做 return users;).then() 因为你没有在这里返回 Promise。 3/ 退货批次相同; 4/ 而不是 fullBatch.forEach();你需要使用 Promise.all()

以上是关于扩展 Firebase Firestore 计划事件的主要内容,如果未能解决你的问题,请参考以下文章

Firebase:Firestore 未在 Cloud Function 的计划函数中更新数据

用于聊天应用的 Firebase 实时数据库或 Firestore? [关闭]

在中国使用 Firebase 身份验证和 Firestore

Firebase 身份验证正在运行,但 Firestore 以缺少权限或权限不足为由拒绝请求

触发电子邮件 google firestore 扩展

用于计划发布的 Firebase 和 GCP Cloud 任务