62

Is it possible to store multiple documents in Firestore with only one request? With this loop it's possible but this would cause one save operation per item in the list.

for (counter in counters) {
    val counterDocRef = FirebaseFirestore.getInstance()
            .document("users/${auth.currentUser!!.uid}/lists/${listId}/counters/${counter.id}")
    val counterData = mapOf(
            "name" to counter.name,
            "score" to counter.score,
    )
    counterDocRef.set(counterData)
}
Asghar Musani
  • 568
  • 4
  • 20
Marcel Bochtler
  • 1,291
  • 1
  • 14
  • 23

4 Answers4

91

From Firebase documentation :

You can also execute multiple operations as a single batch, with any combination of the set(), update(), or delete() methods. You can batch writes across multiple documents, and all operations in the batch complete atomically.

// Get a new write batch
WriteBatch batch = db.batch();

// Set the value of 'NYC'
DocumentReference nycRef = db.collection("cities").document("NYC");
batch.set(nycRef, new City());

// Update the population of 'SF'
DocumentReference sfRef = db.collection("cities").document("SF");
batch.update(sfRef, "population", 1000000L);

// Delete the city 'LA'
DocumentReference laRef = db.collection("cities").document("LA");
batch.delete(laRef);

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

Firestore multiple write operations

Hope it helps..

Finlay Percy
  • 6,763
  • 4
  • 22
  • 28
Yassin
  • 1,049
  • 11
  • 15
  • Yes, that's exactly what I was looking for and unfortunately missed in the documentation. – Marcel Bochtler Oct 07 '17 at 12:24
  • 1
    Is there a way to bulk read, similar to this ability to write, i.e. if I have 10 doc references can I batch get them? Thanks! – Shaun Oct 20 '17 at 17:28
  • 1
    @MarcelBochtler There's no mention in the documentation that a batch operation is billed as a single read. Batching is a way to perform operations atomically (all at once or not at all), but that's different than billing. The billing page that I cite in my answer makes it clear that "You are charged for each document read, write, and delete that you perform with Cloud Firestore." – Doug Stevenson Oct 26 '17 at 11:15
  • @DougStevenson My question did not mention billing. So this answer solves my stated problem. Anyway in my testing I saw that one batch with multiple writes is only charged as one write. But this may change, because like you said, this is not how it is documented. – Marcel Bochtler Oct 31 '17 at 14:16
  • 1
    Billing might have changed. Each write in a batch is charged as one Entity Write from what I saw today. – live-love Jan 09 '19 at 14:33
  • In my case, the document id is dynamically created by Firestore. I have no idea how could this be handled without the ID at my end? Is there any batch support for add() method instead of set(). I checked the API and it is not available. Am I missing anything? – Thamizharasu May 18 '20 at 06:20
  • @Thamizharasu you can create the document with the automated id first and save its ref before and then use set() – Yassin Jun 17 '20 at 12:30
  • Can anyone confirm what is billed for a batch write? from this URL https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes clearly states at the bottom that batch writes are charged individually and are more of an atomic convenience than a billing convenience. – Jangita Jul 04 '20 at 21:16
  • Doesn't work if u want to update multiple fields in same document! – Gentrit Ibishi Sep 08 '22 at 14:42
9

Update some properties on all documents in a collection:

resetScore(): Promise<void> {
  return this.usersCollectionRef.ref.get().then(resp => {
    console.log(resp.docs)
    let batch = this.afs.firestore.batch();

    resp.docs.forEach(userDocRef => {
      batch.update(userDocRef.ref, {'score': 0, 'leadsWithSalesWin': 0, 'leadsReported': 0});
    })
    batch.commit().catch(err => console.error(err));
  }).catch(error => console.error(error))
}
jsaddwater
  • 1,781
  • 2
  • 18
  • 28
2
void createServiceGroups() {
        List<String> serviceGroups = [];

        serviceGroups.addAll([
          'Select your Service Group',
          'Cleaning, Laundry & Maid Services',
          'Movers / Relocators',
          'Electronics & Gadget',
          'Home Improvement & Maintenance',
          'Beauty, Wellness & Nutrition',
          'Weddings',
          'Food & Beverage',
          'Style & Apparel',
          'Events & Entertainment',
          'Photographer & Videographers',
          'Health & Fitness',
          'Car Repairs & Maintenance',
          'Professional & Business Services',
          'Language Lessons',
          'Professional & Hobby Lessons',
          'Academic Lessons',
        ]);
        Firestore db = Firestore.instance;
        // DocumentReference ref = db
        //     .collection("service_groups")
        //     .document(Random().nextInt(10000).toString());

        // print(ref.documentID);

        // Get a new write batch

        for (var serviceGroup in serviceGroups) {
          createDocument(db, "name", serviceGroup);
        }

        print("length ${serviceGroups.length}");
      }

      createDocument(Firestore db, String k, String v) {
        WriteBatch batch = db.batch();
        batch.setData(db.collection("service_groups").document(), {k: v});
        batch.commit();
      }

   createDocument(Firestore db, String k, String v) {
            WriteBatch batch = db.batch();
            batch.setData(db.collection("service_groups").document(), {k: v});
            batch.commit();
          }

This may help you:

 for (var serviceGroup in serviceGroups) {
      createDocument(db,  "name", serviceGroup  );
    }
Rashid Iqbal
  • 1,123
  • 13
  • 13
1

If you are in the need to use add() instead of set, please follow the code below,

public void createMany(List<T> datas) throws CustomException {
    Firestore firestore = connection.firestore();
    CollectionReference colRef = firestore.collection("groups");

    WriteBatch batch = firestore.batch();
    for (T data : datas) {
        batch.create(colRef.document(), data);
    }

    ApiFuture<List<WriteResult>> futureList = batch.commit();
    try {
        for (WriteResult result : futureList.get()) {
            logger.debug("Batch output: {}", result.getUpdateTime());
        }
    } catch (InterruptedException | ExecutionException e) {
        throw new CustomException(500, e.getMessage());
    }
}

This might be useful when you are in the need to generate the id from the firestore db.

Thamizharasu
  • 301
  • 3
  • 13