I am using Firestore, Cloud Functions, and the Firebase emulator with Flutter. In my backend, I have a transaction that reads a profile document and then uses its data to create two relationship documents. However, the onUpdateProfile cloud function is triggered (as seen in the emulator logs) even though the profile document is not updated within the transaction.
Here are the emulator logs:
i functions: Beginning execution of "us-east4-onCreateRelationship"
i functions: Finished "us-east4-onCreateRelationship" in 2.332654ms
i functions: Beginning execution of "us-east4-onCreateRelationship"
i functions: Finished "us-east4-onCreateRelationship" in 371.116441ms
i functions: Beginning execution of "us-east4-onUpdateProfile". <----------
i functions: Finished "us-east4-onUpdateProfile" in 2.047866ms <----------
The transaction code is as follows:
await _firestore.runTransaction((transaction) async {
// read the profile first inside the transaction.
// notice that I am not updating the profile
final docSnapshot =
await transaction.get(_firestore.doc('/users/$id'));
final profile = docSnapshot.data();
if (profile != null) {
// get whatever you want from the profile
final pName = profile['name'] as String;
// create two relationship docs
transaction
..set(_firestore.doc('/users/$uid/relationships/$pid'), {
'authorId': uid,
'pName': pName
// place your properties. I am simplifying the doc
})
..set(_firestore.doc('/users/$pid/relationships/$uid'), {
'authorId': uid,
'pName': myProfile.name
// place your properties. I am simplifying the doc
});
}
});
I changed the implementation to use a batch write:
- Read the profile and extract its data.
- Use the profile data in a batch to create two relationship documents.
This version does not trigger the onUpdateProfile function. Here is the batch code:
// read the profile doc first from firestore
final docSnapshot = await _firestore
doc('/users/$pid')
.withConverter<MyProfile>(
fromFirestore: MyProfile.fromFirestore,
toFirestore: (myProfile, _) => myProfile.toFirestore(),
)
.get();
final profile = docSnapshot.data();
// create two relationship docs using a batch
final batch = _firestore.batch()
..set(_firestore.doc('/users/$uid/relationships/$pid'), {
'authorId': uid,
'pName': profile.name,
// place your properties. I am simplifying the doc
})
..set(_firestore.doc('/users/$pid/relationships/$uid'), {
'authorId': uid,
'pName': myProfile.name,
// place your properties. I am simplifying the doc
});
await batch.commit();
Why does the transaction, which only reads the profile document, trigger an update event in the emulator? I would like to understand whether this behavior is due to the internal mechanics of Firestore transactions or an emulator-specific quirk.