Skip to content

Commit bb01d4b

Browse files
authored
First draft of firestore-basics skill (#9719)
* First draft of firestore-basics skill * Second pass, with more detail * More skill improvements * Omit skills from prettier * PR fixes * incorporating the rules gen strategy developed by the access team * PR fixes
1 parent cf9d531 commit bb01d4b

9 files changed

Lines changed: 1040 additions & 1 deletion

File tree

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ scripts/agent-evals/output
99
scripts/agent-evals/node_modules
1010
scripts/agent-evals/lib
1111
scripts/agent-evals/templates
12-
julesbot
12+
julesbot
13+
skills

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
/scripts/agent-evals/output/**
99
/src/frameworks/docs/**
1010
/prompts
11+
/skills
1112

1213
# Intentionally invalid YAML file:
1314
/src/test/fixtures/extension-yamls/invalid/extension.yaml

skills/firestore-basics/SKILL.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: firestore-basics
3+
description: Comprehensive guide for Firestore basics including provisioning, security rules, and SDK usage. Use this skill when the user needs help setting up Firestore, writing security rules, or using the Firestore SDK in their application.
4+
compatibility: This skill is best used with the Firebase CLI, but does not require it. Install it by running `npm install -g firebase-tools`.
5+
---
6+
7+
# Firestore Basics
8+
9+
This skill provides a complete guide for getting started with Cloud Firestore, including provisioning, securing, and integrating it into your application.
10+
11+
## Provisioning
12+
13+
To set up Cloud Firestore in your Firebase project and local environment, see [provisioning.md](references/provisioning.md).
14+
15+
## Security Rules
16+
17+
For guidance on writing and deploying Firestore Security Rules to protect your data, see [security_rules.md](references/security_rules.md).
18+
19+
## SDK Usage
20+
21+
To learn how to use Cloud Firestore in your application code, choose your platform:
22+
23+
* **Web (Modular SDK)**: [web_sdk_usage.md](references/web_sdk_usage.md)
24+
* **Android (Kotlin)**: [android_sdk_usage.md](references/android_sdk_usage.md)
25+
* **iOS (Swift)**: [ios_sdk_usage.md](references/ios_sdk_usage.md)
26+
27+
## Indexes
28+
29+
For checking index types, query support tables, and best practices, see [indexes.md](references/indexes.md).
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Firestore Android SDK Usage Guide
2+
3+
This guide uses **Kotlin** and **KTX extensions**, which correspond to the modern Android development standards.
4+
5+
## Initialization
6+
7+
```kotlin
8+
// In your Activity or Application class
9+
import com.google.firebase.firestore.ktx.firestore
10+
import com.google.firebase.firestore.SetOptions
11+
import com.google.firebase.ktx.Firebase
12+
13+
val db = Firebase.firestore
14+
15+
// Connect to Emulator
16+
// Use 10.0.2.2 to access localhost from the Android Emulator
17+
if (BuildConfig.DEBUG) {
18+
db.useEmulator("10.0.2.2", 8080)
19+
}
20+
```
21+
22+
## Writing Data
23+
24+
### Set a Document (`set`)
25+
Creates or overwrites a document.
26+
27+
```kotlin
28+
val city = hashMapOf(
29+
"name" to "Los Angeles",
30+
"state" to "CA",
31+
"country" to "USA"
32+
)
33+
34+
db.collection("cities").document("LA")
35+
.set(city)
36+
.addOnSuccessListener { Log.d(TAG, "DocumentSnapshot successfully written!") }
37+
.addOnFailureListener { e -> Log.w(TAG, "Error writing document", e) }
38+
39+
// Merge
40+
db.collection("cities").document("LA")
41+
.set(mapOf("population" to 3900000), SetOptions.merge())
42+
```
43+
44+
### Add a Document with Auto-ID (`add`)
45+
46+
```kotlin
47+
val data = hashMapOf(
48+
"name" to "Tokyo",
49+
"country" to "Japan"
50+
)
51+
52+
db.collection("cities")
53+
.add(data)
54+
.addOnSuccessListener { documentReference ->
55+
Log.d(TAG, "DocumentSnapshot written with ID: ${documentReference.id}")
56+
}
57+
```
58+
59+
### Update a Document (`update`)
60+
61+
```kotlin
62+
val laRef = db.collection("cities").document("LA")
63+
64+
laRef.update("capital", true)
65+
.addOnSuccessListener { Log.d(TAG, "DocumentSnapshot successfully updated!") }
66+
```
67+
68+
### Transactions
69+
Atomic read-modify-write.
70+
71+
```kotlin
72+
db.runTransaction { transaction ->
73+
val sfDocRef = db.collection("cities").document("SF")
74+
val snapshot = transaction.get(sfDocRef)
75+
76+
// Note: You can also use FieldValue.increment() for simple counters
77+
val newPopulation = (snapshot.getDouble("population") ?: 0.0) + 1
78+
transaction.update(sfDocRef, "population", newPopulation)
79+
80+
// Success
81+
null
82+
}.addOnSuccessListener { Log.d(TAG, "Transaction success!") }
83+
.addOnFailureListener { e -> Log.w(TAG, "Transaction failure.", e) }
84+
```
85+
86+
## Reading Data
87+
88+
### Get a Single Document (`get`)
89+
90+
```kotlin
91+
val docRef = db.collection("cities").document("SF")
92+
93+
docRef.get().addOnSuccessListener { document ->
94+
if (document != null && document.exists()) {
95+
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
96+
} else {
97+
Log.d(TAG, "No such document")
98+
}
99+
}
100+
```
101+
102+
### Get Multiple Documents (`get`)
103+
104+
```kotlin
105+
db.collection("cities")
106+
.get()
107+
.addOnSuccessListener { result ->
108+
for (document in result) {
109+
Log.d(TAG, "${document.id} => ${document.data}")
110+
}
111+
}
112+
```
113+
114+
## Realtime Updates
115+
116+
### Listen to Changes (`addSnapshotListener`)
117+
118+
```kotlin
119+
val docRef = db.collection("cities").document("SF")
120+
121+
docRef.addSnapshotListener { snapshot, e ->
122+
if (e != null) {
123+
Log.w(TAG, "Listen failed.", e)
124+
return@addSnapshotListener
125+
}
126+
127+
if (snapshot != null && snapshot.exists()) {
128+
val source = if (snapshot.metadata.hasPendingWrites()) "Local" else "Server"
129+
Log.d(TAG, "$source data: ${snapshot.data}")
130+
} else {
131+
Log.d(TAG, "Current data: null")
132+
}
133+
}
134+
```
135+
136+
## Queries
137+
138+
### Simple and Compound
139+
Note: Compound queries on different fields require an index.
140+
141+
```kotlin
142+
// Simple
143+
db.collection("cities").whereEqualTo("state", "CA")
144+
145+
// Compound (AND)
146+
db.collection("cities")
147+
.whereEqualTo("state", "CA")
148+
.whereGreaterThan("population", 1000000)
149+
```
150+
151+
### Order and Limit
152+
153+
```kotlin
154+
db.collection("cities")
155+
.orderBy("name", Query.Direction.ASCENDING)
156+
.limit(3)
157+
```
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Firestore Indexes Reference
2+
3+
Indexes allow Firestore to ensure that query performance depends on the size of the result set, not the size of the database.
4+
5+
## Index Types
6+
7+
### Single-Field Indexes
8+
Firestore **automatically creates** a single-field index for every field in a document (and subfields in maps).
9+
* **Support**: Simple equality queries (`==`) and single-field range/sort queries (`<`, `<=`, `orderBy`).
10+
* **Behavior**: You generally don't need to manage these unless you want to *exempt* a field.
11+
12+
### Composite Indexes
13+
A composite index stores a sorted mapping of all documents based on an ordered list of fields.
14+
* **Support**: Complex queries that filter or sort by **multiple fields**.
15+
* **Creation**: These are **NOT** automatically created. You must define them manually or via the console/CLI.
16+
17+
## Automatic vs. Manual Management
18+
19+
### What is Automatic?
20+
* Indexes for simple queries.
21+
* Merging of single-field indexes for multiple equality filters (e.g., `where("state", "==", "CA").where("country", "==", "USA")`).
22+
23+
### When Do I Need to Act?
24+
If you attempt a query that requires a composite index, the SDK will throw an error containing a **direct link** to the Firebase Console to create that specific index.
25+
26+
**Example Error:**
27+
> "The query requires an index. You can create it here: https://console.firebase.google.com/project/..."
28+
29+
## Query Support Examples
30+
31+
| Query Type | Index Required |
32+
| :--- | :--- |
33+
| **Simple Equality**<br>`where("a", "==", 1)` | Automatic (Single-Field) |
34+
| **Simple Range/Sort**<br>`where("a", ">", 1).orderBy("a")` | Automatic (Single-Field) |
35+
| **Multiple Equality**<br>`where("a", "==", 1).where("b", "==", 2)` | Automatic (Merged Single-Field) |
36+
| **Equality + Range/Sort**<br>`where("a", "==", 1).where("b", ">", 2)` | **Composite Index** |
37+
| **Multiple Ranges**<br>`where("a", ">", 1).where("b", ">", 2)` | **Composite Index** (and technically limited query support) |
38+
| **Array Contains + Equality**<br>`where("tags", "array-contains", "news").where("active", "==", true)` | **Composite Index** |
39+
40+
## Best Practices & Exemptions
41+
42+
You can **exempt** fields from automatic indexing to save storage or strictly enforce write limits.
43+
44+
### 1. High Write Rates (Sequential Values)
45+
* **Problem**: Indexing fields that increase sequentially (like `timestamp`) limits the write rate to ~500 writes/second per collection.
46+
* **Solution**: If you don't query on this field, **exempt** it from simple indexing.
47+
48+
### 2. Large String/Map/Array Fields
49+
* **Problem**: Indexing limits (40k entries per doc). Indexing large blobs wastes storage.
50+
* **Solution**: Exempt large text blobs or huge arrays if they aren't used for filtering.
51+
52+
### 3. TTL Fields
53+
* **Problem**: TTL (Time-To-Live) deletion can cause index churn.
54+
* **Solution**: Exempt the TTL timestamp field from indexing if you don't query it.
55+
56+
## Management
57+
58+
### Config files
59+
Your indexes should be defined in `firestore.indexes.json` (pointed to by `firebase.json`).
60+
61+
```json
62+
{
63+
"indexes": [
64+
{
65+
"collectionGroup": "cities",
66+
"queryScope": "COLLECTION",
67+
"fields": [
68+
{ "fieldPath": "country", "order": "ASCENDING" },
69+
{ "fieldPath": "population", "order": "DESCENDING" }
70+
]
71+
}
72+
],
73+
"fieldOverrides": []
74+
}
75+
```
76+
77+
### CLI Commands
78+
79+
Deploy indexes only:
80+
```bash
81+
firebase deploy --only firestore:indexes
82+
```

0 commit comments

Comments
 (0)