Skip to content

Commit 46d18fa

Browse files
Merge pull request #1383 from firebase/docs/firestore-transform-ordering
docs(firestore): document Firestore query and populateCell transforms
2 parents e76b9a5 + b58fac7 commit 46d18fa

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

FirebaseFirestoreUI/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,56 @@ self.dataSource = collectionView.bind(to: query) { collectionView, indexPath, sn
4545
}
4646
```
4747

48+
### Transforming and ordering data
49+
50+
Firestore UI binds the **results of a Firestore query** to a table or collection
51+
view. It does not provide client-side `map` / `filter` / `sort` transforms on
52+
those results (Firebase Database UI's FUISortedArray has no Firestore
53+
counterpart). Shape data for display in one of these places instead:
54+
55+
1. **In the query** — filter, order, and limit with Firestore query APIs before
56+
binding. Prefer this for anything that affects which documents appear or in
57+
what order.
58+
2. **In `populateCell`** — map fields onto cell UI when dequeuing. Prefer this
59+
for presentation-only changes (labels, formatting, hiding empty fields).
60+
61+
#### Query-side ordering and limits
62+
63+
```swift
64+
// Newest-first list
65+
let query = Firestore.firestore()
66+
.collection("posts")
67+
.order(by: "createdAt", descending: true)
68+
.limit(to: 50)
69+
70+
self.dataSource = tableView.bind(to: query) { tableView, indexPath, snapshot in
71+
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier",
72+
for: indexPath)
73+
let data = snapshot.data()
74+
cell.textLabel?.text = data?["title"] as? String
75+
return cell
76+
}
77+
```
78+
79+
For a chat-style feed (latest N messages, oldest → newest in the list), use
80+
`limit(toLast:)` with ascending order:
81+
82+
```swift
83+
let query = Firestore.firestore()
84+
.collection("rooms").document(roomId).collection("messages")
85+
.order(by: "timestamp")
86+
.limit(toLast: 30)
87+
88+
self.dataSource = tableView.bind(to: query) { tableView, indexPath, snapshot in
89+
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier",
90+
for: indexPath)
91+
/* populate cell */
92+
return cell
93+
}
94+
```
95+
96+
Keep queries bounded. When a query changes, FUIBatchedArray falls back to a Longest Common Subsequence (LCS) algorithm with O(N^2) complexity on the main thread to compute the diff. Unbounded queries can easily block the main thread and cause UI hangs.
97+
4898
#### FUIBatchedArray
4999

50100
`FUIBatchedArray` powers all of the updating logic in the data source classes

0 commit comments

Comments
 (0)