firebase / firebase/firebase-ios-sdk
Firestore batch deletes emit a snapshot per delete
- Dominant language
- C++
- Stars
- 6.7k
- Forks
- 1.8k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 72
Description
### Description
Batch deletes cause the firestore ios client to emit a snapshot for every individual delete, which creates an exponential (edit: N + N-1 + N-2, [triangular](https://en.wikipedia.org/wiki/Triangular_number)?) amount work decoding every document in each snapshot.
I would expect to get a single snapshot for the single batch delete. [Firebase's documentation](https://firebase.google.com/docs/firestore/manage-data/transactions#batched-writes) says "A batch of writes completes atomically and can write to multiple documents". The documentation seems to recommend batch writes over transactions for cases where you're not reading: "Like transactions, batched writes are atomic. Unlike transactions, batched writes do not need to ensure that read documents remain un-modified which leads to fewer failure cases."
I'd also expect that if multiple changes happen in the background, the next time the ios client connects, it emits a single snapshot with that complete set of changes, not one snapshot per change.
### Reproducing the issue
Write 500 documents to a Firestore collection using Firestore's batch API with an admin SDK.
Observe the collection in a snapshot listener on iOS.
Receive a single snapshot update from network with 500 documents (WAI)
Then, using the same batch API, delete all 500 visits, roughly:
```
all_documents = list(collection.list_documents())
batch = db.batch()
for doc in all_documents:
batch.delete(doc)
batch.commit()
```
On the client, add a snapshot listener to the collection:
```
let options = SnapshotListenOptions().withIncludeMetadataChanges(includeMetadataChanges)
db.collectionGroup("collection")
.whereField(...)
.order(by: "soc_date", descending: true)
.addSnapshotListener(options: options) { querySnapshot, error in
Log("Got snapshot, from cache: \(snapshot?.metadata.isFromCache ?? "nil"));
}
```
Receive separate snapshots marked "from cache" for every single delete:
```
Got snapshot, from cache: 1, documents: 500
Got snapshot, from cache: 1, documents: 499
Got snapshot, from cache: 1, documents: 498
Got snapshot, from cache: 1, documents: 497
Got snapshot, from cache: 1, documents: 496
...
```
If you do this with a collection of 5000 items and you decode every item in each snapshot on the client, you end up decoding ~12 million documents during this process (5000 + 4999 + 4998 etc). Firebase also seems to emit the snapshots quite slowly (< 1 per second at the start). This is pretty catastrophic for app performance and users' battery life.
I also see this behavior for Android FWIW.
### Firebase SDK Version
10.24.0
### Xcode Version
15.0.1
### Installation Method
Swift Package Manager
### Firebase Product(s)
Firestore
### Targeted Platforms
iOS
### Relevant Log Output
_No response_
### If using Swift Package Manager, the project's Package.resolved
Expand Package.resolved snippet
```json
Replace this line with the contents of your Package.resolved.
```
### If using CocoaPods, the project's Podfile.lock
Expand Podfile.lock snippet
```yml
Replace this line with the contents of your Podfile.lock!
```
Contributor guide
Assessment
This issue has not been assessed yet.