如何在 Firestore 中进行批量更新

Posted

技术标签:

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

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

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

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

【问题讨论】:

您链接到的文档有一个批量写入的示例。 我了解如何使用批量写入。我在问如何为集合中的每个文档执行更新。 【参考方案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 你为什么这么说?如果您在某些实践方面遇到困难,请在 *** 上发布一个新问题,以便我和其他 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()

以上是关于如何在 Firestore 中进行批量更新的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 node.js 在 mySQL 中进行批量更新

如何在仅更新特定字段的dynamo db中进行批量更新

如何使用 Java 对 MongoDB 中的文档进行批量更新?

如何在 Controller 的 java spring JPA 中进行批量更新

MongoDB批量更新不同查询条件的数据

WPF DataGrid - 如何暂停数据绑定中的 UI 更新并稍后进行批量更新