yuval
yuval

Reputation: 3088

Firestore: How can I use a transaction to read and then write to a document that I don't have a reference to?

I have a document which i fetch with a query like this:

var myPromise = db.collection("games").where("started", "==", false).orderBy("created").limit(1).get()

I need to create a transaction where a read from this document and then write. For example(taken from the documentation):

// Create a reference to the SF doc.
var sfDocRef = db.collection("cities").doc("SF");

// Uncomment to initialize the doc.
// sfDocRef.set({ population: 0 });

return db.runTransaction(function(transaction) {
    // This code may get re-run multiple times if there are conflicts.
    return transaction.get(sfDocRef).then(function(sfDoc) {
        if (!sfDoc.exists) {
            throw "Document does not exist!";
        }

        // Add one person to the city population.
        // Note: this could be done without a transaction
        //       by updating the population using FieldValue.increment()
        var newPopulation = sfDoc.data().population + 1;
        transaction.update(sfDocRef, { population: newPopulation });
    });
}).then(function() {
    console.log("Transaction successfully committed!");
}).catch(function(error) {
    console.log("Transaction failed: ", error);
});

I want to replace the sfDocRef variable with the myPromise variable but I can't since one is a document reference and the other is a promise. How can I create a transaction on the document that myPromise represents?

Upvotes: 0

Views: 553

Answers (2)

Frank van Puffelen
Frank van Puffelen

Reputation: 598827

You need to wait for the promise to resolve, for example by attaching a then callback:

myPromise.then((querySnapshot) => {
  let ref = querySnapshot.documents[0].ref;
  return db.runTransaction(function(transaction) {
    return transaction.get(ref).then(function(sfDoc) {
        if (!sfDoc.exists) {
            throw "Document does not exist!";
        }
        var newPopulation = sfDoc.data().population + 1;
        transaction.update(sfDocRef, { population: newPopulation });
    });
  }).then(function() {
    console.log("Transaction successfully committed!");
  }).catch(function(error) {
    console.log("Transaction failed: ", error);
  });
});

This querySnapshot.documents[0].ref assumes that there's only one matching document, or that you only care about the first document. If there may be more you care about, you'll need to loop over the documents in the query snapshot.

You'll still need to get the specific document inside the transaction if (and only if) you want the transaction to ensure this document was unmodified between the query and when you write it in the transaction. If that is not needed, you can use the QueryDocumentSnapshot from the QuerySnapshot.

Upvotes: 1

Doug Stevenson
Doug Stevenson

Reputation: 317467

Once you actually execute that query, the reference is easily available. You can simply:

  1. Execute the query as you are now
  2. Find the DocumentSnapshot in the query results (as you normally would when handling query results)
  3. Use the ref property of the DocumentSnapshot to get the document's reference, which is a DocumentReference
  4. Use that reference in the transaction.

Upvotes: 0

Related Questions