【问题标题】:How to do a bulk update in Firestore如何在 Firestore 中进行批量更新
【发布时间】:2018-04-01 14:34:53
【问题描述】:

我正在使用 Cloud Firestore 并拥有一组文档。对于集合中的每个文档,我想更新其中一个字段。

使用事务来执行更新效率低下,因为我在更新时不需要读取任何数据。

批量更新似乎是正确的方向,但是文档不包含一次更新多个文档的示例。见这里:Batched Writes

【问题讨论】:

  • 您链接到的文档有一个批量写入的示例。
  • 我了解如何使用批量写入。我在问如何为集合中的每个文档执行更新。

标签: java firebase firebase-realtime-database google-cloud-firestore


【解决方案1】:

如果您使用过 Firebase 数据库,则不可能以原子方式写入完全单一的单独位置,这就是您必须使用批量写入的原因,这意味着要么所有操作都成功,要么不应用任何操作。

关于 Firestore,所有操作现在都以原子方式处理。但是,您可以将多个写入操作作为包含 set()、update() 或 delete() 操作的任意组合的单个批处理执行。一批写入原子完成,可以写入多个文档。

这是一个关于写入、更新和删除操作的批处理操作的简单示例。

WriteBatch batch = db.batch();

DocumentReference johnRef = db.collection("users").document("John");
batch.set(johnRef, new User());

DocumentReference maryRef = db.collection("users").document("Mary");
batch.update(maryRef, "Anna", 20); //Update name and age

DocumentReference alexRef = db.collection("users").document("Alex");
batch.delete(alexRef);

batch.commit().addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
        // ...
    }
});

在批处理对象上调用commit() 方法意味着您提交整个批处理。

【讨论】:

  • 感谢您的快速回复,但我的问题是如何对集合中的每个文档执行批量更新。该答案重申了我提供的文档链接中所述的内容,该文档对单个文档执行单独写入。
  • 所以为了增加一堆匹配查询的文档的计数,您必须将每个文档读入内存,然后将每个文档写回?自 1995 年以来,您可以使用 MySQL update directly into the database,MongoDB supports multi-document updates too - 但 Firestore 不能?进步很大,惊艳数据库,太棒了!
  • @DanDascalescu 不,你是直接写的。你为什么说你需要先阅读它?
  • @CharlieMartin 是的,每个写入的文档都算作一次写入操作。
  • @AhmedSaeed 你为什么这么说?如果您在某些实践方面遇到困难,请在 StackOverflow 上发布一个新问题,以便我和其他 Firebase 开发人员可以查看它。
【解决方案2】:

我一直在寻找解决方案,但没有找到,所以我做了这个,如果有人感兴趣的话。

public boolean bulkUpdate() {
  try {
    // see https://firebase.google.com/docs/firestore/quotas#writes_and_transactions
    int writeBatchLimit = 500;
    int totalUpdates = 0;

    while (totalUpdates % writeBatchLimit == 0) {
      WriteBatch writeBatch = this.firestoreDB.batch();

      List<QueryDocumentSnapshot> documentsInBatch =
          this.firestoreDB.collection("animals")
              .whereEqualTo("species", "cat")
              .limit(writeBatchLimit)
              .get()
              .get()
              .getDocuments();

      if (documentsInBatch.isEmpty()) {
        break;
      }

      documentsInBatch.forEach(
          document -> writeBatch.update(document.getReference(), "hasTail", true));

      writeBatch.commit().get();

      totalUpdates += documentsInBatch.size();
    }

    System.out.println("Number of updates: " + totalUpdates);

  } catch (Exception e) {
    return false;
  }
  return true;
}

【讨论】:

    【解决方案3】:

    在 SQL 中你可以做到

    UPDATE table_name
    SET column1 = value1, column2 = value2, ...
    WHERE condition;
    

    WHERE 是可选的 - 因此您可以将所有字段设置为特定值或为选择的行设置所有字段,但您不需要首先获取对行的引用。

    例如,如果内容需要审核,您可以在所有行的审核列中设置一个标志。

    在 Firestore 中,我认为没有办法写入集合。

    https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference

    所有收集方法都是添加文档、获取文档引用或过滤文档搜索的方法。

    据我所知,如果不先获取对它们的引用,就无法更新 firestore 中的一组文档。

    批量写入加快了这一速度,因为您一次可以更新 500 个文档。

    【讨论】:

    • 如果集合有超过 500 个文档怎么办?就我而言,我正在使用云功能来执行此操作,但我不确定处理有大量文档的情况的最佳方法是什么。
    • firebase.google.com/docs/firestore/manage-data/… 可以做多个批次。如果您不进行批处理,您将针对每条记录向服务器发送响应。使用批次,您一次最多可以向服务器发送 500 个,这要快得多。只需计算您正在处理的记录数量,然后每 500 次执行一次 batch.commit()
    猜你喜欢
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 2016-09-21
    • 2018-04-09
    • 2012-09-21
    相关资源
    最近更新 更多