Cloud Firestore in Flutter
Cloud Firestore is a flexible, scalable NoSQL cloud database provided by Firebase. It stores application data in collections and documents and allows Flutter applications to create, read, update, delete, query, and listen to data in real time.
Cloud Firestore can be used for applications such as user profiles, products, orders, chat applications, task management systems, social applications, blogs, booking systems, and dashboards. It supports real-time updates, expressive queries, hierarchical data structures, and offline capabilities. Firebase Cloud Firestore Documentation
1. What is Cloud Firestore?
Cloud Firestore is a NoSQL document database designed for mobile, web, and server applications. Instead of storing data in traditional rows and columns, Firestore stores data inside documents that are organized into collections.
For example, a user collection may contain multiple user documents:
users
├── user001
├── user002
├── user003
└── user004
Each document can contain fields such as name, email, age, phone number, and other application-specific information.
2. Firestore Data Model
The basic structure of Cloud Firestore is:
Firestore
|
+-- Collection
|
+-- Document
|
+-- Fields
|
+-- Subcollection
Example
users
|
+-- user123
|
+-- name: "John"
+-- email: "[email protected]"
+-- age: 25
|
+-- orders
|
+-- order001
+-- order002
3. Collection
A collection is a group of related documents.
For example:
users
products
orders
messages
courses
A collection does not normally store application data directly as fields. Instead, it contains documents.
4. Document
A document is a record containing fields and values.
Example:
{
"name": "John Doe",
"email": "[email protected]",
"age": 25,
"isActive": true
}
A document has a unique document ID within its collection.
5. Fields
Fields contain the actual values stored inside a document.
| Field |
Example Value |
Type |
| name |
John Doe |
String |
| age |
25 |
Number |
| isActive |
true |
Boolean |
| skills |
["Flutter","Dart"] |
Array |
| address |
{city: "Mumbai"} |
Map |
| createdAt |
Timestamp |
Timestamp |
6. Subcollections
A document can contain subcollections. Subcollections are useful when data logically belongs to a particular document.
For example:
users
|
+-- user123
|
+-- name: "John"
+-- email: "[email protected]"
|
+-- orders
|
+-- order001
+-- order002
Here, orders is a subcollection inside the user123 document.
7. Why Use Cloud Firestore with Flutter?
- Cloud-hosted NoSQL database.
- Easy integration with Flutter through the Firebase FlutterFire plugin.
- Supports real-time data updates.
- Supports one-time data reads.
- Supports filtering and sorting.
- Supports hierarchical collections and subcollections.
- Provides offline data support on supported platforms.
- Integrates with Firebase Authentication.
- Can be protected with Firebase Security Rules.
- Suitable for small applications and applications that need to scale.
Firestore supports flexible data structures, expressive queries, real-time listeners, and offline capabilities. Learn more about Cloud Firestore
8. Prerequisites
Before using Cloud Firestore in Flutter, you should have:
- Firebase configured with the Flutter application.
- The Cloud Firestore database created in Firebase Console.
For current Firebase Flutter setup instructions, see Get Started with Firebase in Flutter.
9. Add Cloud Firestore to Flutter
From the Flutter project directory, run:
flutter pub add cloud_firestore
After adding a Firebase Flutter plugin, Firebase's current setup flow uses flutterfire configure to keep the application's Firebase configuration up to date. Firebase Flutter Setup
10. Import Cloud Firestore
import 'package:cloud_firestore/cloud_firestore.dart';
11. Get Firestore Instance
The main Firestore instance can be accessed using FirebaseFirestore.instance.
final FirebaseFirestore db = FirebaseFirestore.instance;
You can also directly use:
FirebaseFirestore.instance
12. Initialize Firebase
Firebase should be initialized before using Firestore.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
In a typical FlutterFire project, Firebase initialization uses the generated firebase_options.dart configuration.
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
13. Create a Firestore Database
- Open Firebase Console.
- Select your Firebase project.
- Open Firestore Database.
- Create a database.
- Choose the appropriate database configuration and location.
- Configure Security Rules according to your application's requirements.
Firestore data can also be managed directly from the Firebase Console. Manage Cloud Firestore with Firebase Console
14. Add Data to Firestore
There are several ways to add data to Firestore. You can specify a document ID yourself or allow Firestore to generate one automatically. Add Data to Cloud Firestore
15. Add Document with Auto-Generated ID
The add() method creates a new document and automatically generates its document ID.
await FirebaseFirestore.instance
.collection('users')
.add({
'name': 'John Doe',
'email': '[email protected]',
'age': 25,
});
The resulting structure may look like:
users
|
+-- automatically-generated-id
|
+-- name: John Doe
+-- email: [email protected]
+-- age: 25
16. Add Document with Custom ID
Use doc() when you want to specify the document ID.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'email': '[email protected]',
'age': 25,
});
The document ID in this example is user001.
17. Set Data
The set() method writes data to a document.
final userRef = FirebaseFirestore.instance
.collection('users')
.doc('user001');
await userRef.set({
'name': 'John Doe',
'email': '[email protected]',
});
18. Set Data with Merge
When you want to update selected fields without replacing the complete document, you can use merge behavior.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'age': 26,
}, SetOptions(merge: true));
This keeps other existing fields in the document while updating the specified field.
19. Firestore Data Types
Firestore supports several common data types, including strings, booleans, numbers, arrays, maps, timestamps, null values, document references, and other supported types.
final data = {
'name': 'John',
'age': 25,
'isStudent': false,
'skills': ['Flutter', 'Dart'],
'address': {
'city': 'Mumbai',
'country': 'India',
},
'createdAt': Timestamp.now(),
'description': null,
};
20. Read a Single Document
Use get() to retrieve a document once.
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
if (doc.exists) {
print(doc.data());
}
Firestore supports one-time reads as well as real-time listeners. Get Data with Cloud Firestore
21. Access Document Data
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
final data = doc.data();
if (data != null) {
print(data['name']);
print(data['email']);
print(data['age']);
}
22. Check Whether a Document Exists
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
if (doc.exists) {
print('Document exists');
} else {
print('Document does not exist');
}
23. Read All Documents from a Collection
Use a collection reference and get() to retrieve documents from a collection.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
for (final doc in snapshot.docs) {
print(doc.id);
print(doc.data());
}
24. Get Document ID
Each Firestore document has an ID that can be accessed through doc.id.
for (final doc in snapshot.docs) {
print('Document ID: ${doc.id}');
}
25. Convert Firestore Data into a List
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
final users = snapshot.docs.map((doc) {
return {
'id': doc.id,
...doc.data(),
};
}).toList();
26. Display Firestore Data with FutureBuilder
FutureBuilder is useful for displaying data obtained through a one-time Firestore request.
FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.get(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return const Center(
child: Text('Something went wrong'),
);
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return const Center(
child: Text('No users found'),
);
}
final users = snapshot.data!.docs;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index].data();
return ListTile(
title: Text(user['name'] ?? ''),
subtitle: Text(user['email'] ?? ''),
);
},
);
},
)
27. Real-Time Firestore Data
Firestore supports real-time listeners. A listener receives an initial snapshot and then receives updates when the listened-to data changes.
FirebaseFirestore.instance
.collection('users')
.snapshots()
.listen((snapshot) {
for (final doc in snapshot.docs) {
print(doc.data());
}
});
Real-time listeners are useful for chat applications, live dashboards, notifications, collaborative applications, and other interfaces where data can change while the screen is open.
28. StreamBuilder with Firestore
StreamBuilder can be used to automatically rebuild the UI when Firestore data changes.
StreamBuilder>>(
stream: FirebaseFirestore.instance
.collection('users')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return const Center(
child: Text('Error loading users'),
);
}
final users = snapshot.data?.docs ?? [];
if (users.isEmpty) {
return const Center(
child: Text('No users found'),
);
}
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index].data();
return ListTile(
title: Text(user['name'] ?? ''),
subtitle: Text(user['email'] ?? ''),
);
},
);
},
)
29. Update Firestore Data
The update() method changes selected fields in an existing document.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'age': 26,
'isActive': true,
});
30. Update a Single Field
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'name': 'John Smith',
});
31. Delete a Document
Use delete() to remove a document.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.delete();
32. Delete a Field
You can remove a field from a document using FieldValue.delete().
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'temporaryField': FieldValue.delete(),
});
33. Firestore CRUD Operations
CRUD stands for Create, Read, Update, and Delete.
| Operation |
Firestore Method |
| Create |
add() / set() |
| Read |
get() / snapshots() |
| Update |
update() |
| Delete |
delete() |
34. Query Firestore Data
Firestore queries allow you to retrieve only documents matching particular conditions. Queries can be combined with filtering, sorting, limits, and other supported query features. Cloud Firestore Query Documentation
35. Query Using where()
The where() method can filter documents based on field values.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where('age', isGreaterThan: 18)
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
36. Equality Query
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where('city', isEqualTo: 'Mumbai')
.get();
37. Multiple Query Conditions
Firestore supports compound queries when the selected fields and query structure are supported.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where('isActive', isEqualTo: true)
.where('age', isGreaterThan: 18)
.get();
Some compound queries may require an index. If Firestore requires an index, the error response can provide a link to create the required index.
38. Sorting Data with orderBy()
Use orderBy() to sort query results.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.orderBy('name')
.get();
Descending Order
final snapshot = await FirebaseFirestore.instance
.collection('users')
.orderBy('name', descending: true)
.get();
39. Limit Query Results
Use limit() when you only need a specific number of documents.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.limit(10)
.get();
Limiting results can be useful for dashboards, previews, pagination, and performance-conscious screens.
40. Query with Multiple Conditions and Sorting
final snapshot = await FirebaseFirestore.instance
.collection('products')
.where('category', isEqualTo: 'Mobile')
.where('price', isLessThan: 50000)
.orderBy('price')
.get();
Query structure must follow Firestore's query constraints and indexing requirements.
41. Query Using whereIn
Some queries can match a field against multiple values using supported operators such as whereIn.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where(
'role',
whereIn: ['admin', 'manager'],
)
.get();
42. Array Queries
For fields containing arrays, Firestore supports operators such as arrayContains.
final snapshot = await FirebaseFirestore.instance
.collection('courses')
.where(
'skills',
arrayContains: 'Flutter',
)
.get();
43. Search Example
A Firestore query can be used to filter data according to supported query operations.
final snapshot = await FirebaseFirestore.instance
.collection('products')
.where(
'category',
isEqualTo: 'Laptop',
)
.get();
For advanced full-text search requirements, a dedicated search solution may be more appropriate than relying on simple Firestore field filtering.
44. Firestore with Firebase Authentication
Cloud Firestore is commonly used together with Firebase Authentication. Authentication identifies the user, while Firestore stores application data associated with that user.
Example:
Authentication
|
v
Firebase User UID
|
v
Firestore
|
v
users/{uid}
Example
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.set({
'email': user.email,
'name': 'John Doe',
});
}
45. User-Specific Data
A common pattern is to use the authenticated user's UID as the Firestore document ID.
users
|
+-- AUTH_USER_UID
|
+-- name
+-- email
+-- phone
+-- createdAt
This makes it straightforward to locate the current user's document.
46. Firestore Security Rules
Security Rules are essential for protecting Firestore data. For Flutter mobile and web clients, Firebase recommends using Firebase Authentication together with Cloud Firestore Security Rules to control access and validate data. Cloud Firestore Security Documentation
A basic authenticated-user rule can look like:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
}
}
This pattern allows an authenticated user to access the user document whose ID matches their Firebase Authentication UID.
47. Important Security Rule Concept
Firestore Security Rules are not filters. A query must satisfy the constraints required by the rules for all potential documents that could be returned. A query that could return unauthorized documents can fail rather than simply filtering those documents out. Securely Query Cloud Firestore Data
48. Example of Query-Compatible Security
match /stories/{storyId} {
allow read: if request.auth != null
&& resource.data.author == request.auth.uid;
}
The corresponding client query should constrain the author field:
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
final snapshot = await FirebaseFirestore.instance
.collection('stories')
.where(
'author',
isEqualTo: user.uid,
)
.get();
}
This query structure reflects the access condition enforced by the rule.
49. Server-Side Access vs Mobile/Web Access
Cloud Firestore Security Rules apply to supported mobile and web client access. Server client libraries use IAM and do not rely on Cloud Firestore Security Rules in the same way. Server-side applications should therefore be secured using the appropriate Google Cloud IAM configuration. Firestore Security Overview
50. Timestamp in Firestore
Firestore supports timestamp values.
await FirebaseFirestore.instance
.collection('posts')
.add({
'title': 'Flutter Course',
'createdAt': Timestamp.now(),
});
You can read the timestamp:
final data = doc.data();
final Timestamp? timestamp = data?['createdAt'];
if (timestamp != null) {
final date = timestamp.toDate();
print(date);
}
51. Server Timestamp
When you want Firestore to assign the server-side timestamp, use FieldValue.serverTimestamp().
await FirebaseFirestore.instance
.collection('posts')
.add({
'title': 'Flutter Course',
'createdAt': FieldValue.serverTimestamp(),
});
52. Increment Numeric Values
Firestore supports atomic numeric increments.
await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.update({
'views': FieldValue.increment(1),
});
This can be useful for counters such as views, likes, or quantities when used according to the application's concurrency and data-model requirements.
53. Array Operations
Firestore supports atomic array operations such as adding or removing values.
Add an Item to an Array
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'skills': FieldValue.arrayUnion(['Firebase']),
});
Remove an Item from an Array
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'skills': FieldValue.arrayRemove(['Firebase']),
});
54. Nested Objects
Firestore documents can contain nested map structures.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John',
'address': {
'city': 'Mumbai',
'country': 'India',
'postalCode': '400001',
},
});
55. Access Nested Data
final data = doc.data();
final address = data?['address'];
if (address != null) {
print(address['city']);
print(address['country']);
}
56. Subcollection Example
final userRef = FirebaseFirestore.instance
.collection('users')
.doc('user001');
await userRef
.collection('orders')
.doc('order001')
.set({
'product': 'Flutter Course',
'price': 5000,
'status': 'pending',
});
The resulting structure is:
users
|
+-- user001
|
+-- orders
|
+-- order001
|
+-- product
+-- price
+-- status
57. Read a Subcollection
final snapshot = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.collection('orders')
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
58. Real-Time Chat Example
Firestore real-time listeners can be used for chat applications.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('messages')
.orderBy('createdAt')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
final messages = snapshot.data!.docs;
return ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index].data();
return ListTile(
title: Text(message['text'] ?? ''),
subtitle: Text(message['sender'] ?? ''),
);
},
);
},
)
59. Pagination Concept
When a collection contains many documents, loading everything at once may not be appropriate. Firestore supports query cursors that can be used to retrieve data in pages.
A common pagination flow is:
First Page
|
v
Get Documents
|
v
Remember Last Document
|
v
Request Next Page
|
v
Display More Documents
Pagination should be designed around the application's sorting and filtering requirements.
60. Transactions
Transactions are useful when a group of reads and writes needs to operate consistently based on the current database values.
await FirebaseFirestore.instance.runTransaction(
(transaction) async {
final ref = FirebaseFirestore.instance
.collection('products')
.doc('product001');
final snapshot = await transaction.get(ref);
final currentStock = snapshot.data()?['stock'] ?? 0;
if (currentStock > 0) {
transaction.update(ref, {
'stock': currentStock - 1,
});
}
},
);
61. Batch Writes
Batch writes can be used when multiple write operations should be sent together.
final batch = FirebaseFirestore.instance.batch();
final userRef = FirebaseFirestore.instance
.collection('users')
.doc('user001');
final orderRef = FirebaseFirestore.instance
.collection('orders')
.doc('order001');
batch.set(userRef, {
'name': 'John',
});
batch.set(orderRef, {
'product': 'Flutter Course',
});
await batch.commit();
62. Error Handling
Firestore operations should handle errors because network problems, permissions, invalid operations, and other conditions can cause a request to fail.
try {
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John',
});
} catch (e) {
print('Firestore error: $e');
}
63. Firestore Exception Handling
You can handle Firestore-specific exceptions using FirebaseException.
try {
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
} on FirebaseException catch (e) {
print('Code: ${e.code}');
print('Message: ${e.message}');
} catch (e) {
print('Unexpected error: $e');
}
64. Loading, Error, Empty, and Success States
A Firestore-based screen should generally handle four important states:
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return const Text('Unable to load data');
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return const Text('No data available');
}
return const Text('Data loaded successfully');
65. Convert Firestore Documents to Dart Models
For larger applications, it is better to convert Firestore documents into Dart model classes instead of passing raw maps throughout the UI.
User Model
class UserModel {
final String id;
final String name;
final String email;
UserModel({
required this.id,
required this.name,
required this.email,
});
factory UserModel.fromFirestore(
DocumentSnapshot> doc,
) {
final data = doc.data() ?? {};
return UserModel(
id: doc.id,
name: data['name'] ?? '',
email: data['email'] ?? '',
);
}
}
66. Using the User Model
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
final users = snapshot.docs
.map(UserModel.fromFirestore)
.toList();
for (final user in users) {
print(user.name);
print(user.email);
}
67. Firestore Service Class
Firestore operations can be separated into a service class.
class UserService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
Future addUser({
required String id,
required String name,
required String email,
}) async {
await _db.collection('users').doc(id).set({
'name': name,
'email': email,
'createdAt': FieldValue.serverTimestamp(),
});
}
Future>> getUser(
String id,
) {
return _db.collection('users').doc(id).get();
}
Future updateUser(
String id,
Map data,
) {
return _db.collection('users').doc(id).update(data);
}
Future deleteUser(String id) {
return _db.collection('users').doc(id).delete();
}
}
68. Recommended Project Structure
lib/
├── main.dart
├── firebase_options.dart
├── models/
│ ├── user_model.dart
│ └── product_model.dart
├── services/
│ ├── auth_service.dart
│ └── firestore_service.dart
├── screens/
│ ├── home_screen.dart
│ ├── users_screen.dart
│ └── products_screen.dart
├── widgets/
│ ├── user_card.dart
│ └── product_card.dart
└── repositories/
└── user_repository.dart
69. Firestore and Flutter UI
A common Flutter architecture separates the UI from database operations.
Flutter UI
|
v
Controller / ViewModel
|
v
Repository / Service
|
v
Cloud Firestore
|
v
Firebase Backend
This structure makes the code easier to test, maintain, and expand as the application grows.
70. Example Product Application
Suppose an application stores products in Firestore:
products
|
+-- product001
| +-- name: "Laptop"
| +-- price: 65000
| +-- category: "Electronics"
|
+-- product002
+-- name: "Phone"
+-- price: 35000
+-- category: "Electronics"
Add Product
await FirebaseFirestore.instance
.collection('products')
.add({
'name': 'Laptop',
'price': 65000,
'category': 'Electronics',
});
Read Products
final snapshot = await FirebaseFirestore.instance
.collection('products')
.get();
Update Product
await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.update({
'price': 62000,
});
Delete Product
await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.delete();
71. Offline Support
Cloud Firestore provides offline capabilities on supported platforms. The client can cache data that the application is actively using and can continue to read, write, listen to, and query cached data while offline. When connectivity returns, local changes are synchronized with the backend. Firestore Offline Data Documentation
Offline behavior should still be considered when designing user interfaces because users may temporarily have no network connection.
72. Firestore Console
The Firebase Console provides a visual interface for managing Firestore data.
You can use the console to:
- Manage indexes and database configuration.
Firestore data can be managed from the Firestore Data tab in the Firebase Console. Firestore Console Documentation
73. Firestore Indexes
Indexes help Firestore efficiently execute supported queries. Some compound queries require an index. When a required index is missing, Firestore can return an error containing a link to create the required index.
When designing queries, understand the fields used for filtering and sorting so that required indexes can be configured appropriately.
74. Firestore Security Best Practices
- Do not leave production Firestore data publicly readable and writable.
- Use Firebase Authentication for user identity.
- Use Security Rules to control document access.
- Use UID-based rules for user-specific documents.
- Validate incoming data with Security Rules where appropriate.
- Design queries to satisfy the constraints imposed by Security Rules.
- Use App Check where appropriate as an additional protection layer.
- Do not place secret server credentials inside a Flutter application.
- Review rules before releasing the application.
Firebase recommends Authentication and Security Rules for mobile and web client access to Firestore. Firestore Security Rules Overview
75. Common Firestore Mistakes
| Mistake |
Better Approach |
| Using incorrect collection/document paths |
Keep the Firestore data model clearly documented. |
| Loading an entire large collection unnecessarily |
Use filtering, limits, pagination, and appropriate queries. |
| Ignoring loading and error states |
Handle loading, error, empty, and success states. |
| Using raw maps everywhere |
Use Dart model classes for larger applications. |
| Ignoring Security Rules |
Design and test rules before production. |
| Assuming Security Rules filter query results |
Make queries satisfy the constraints required by the rules. |
| Calling database operations unnecessarily |
Use appropriate state management and caching patterns. |
| Ignoring offline behavior |
Design the UI to handle temporary network issues. |
76. Firestore vs Realtime Database
| Feature |
Cloud Firestore |
Realtime Database |
| Data Model |
Collections and documents |
JSON tree |
| Queries |
Rich querying capabilities |
Query capabilities differ |
| Real-Time Updates |
Supported |
Supported |
| Offline Support |
Supported on supported client platforms |
Supported |
| Hierarchical Data |
Documents and subcollections |
Nested JSON structure |
| Security |
Security Rules |
Security Rules |
The appropriate Firebase database depends on the application's data model, query requirements, real-time needs, and other technical considerations.
77. Mini Project: Flutter User Management App
Create a Flutter application that uses Firebase Authentication and Cloud Firestore to manage users.
Required Features
- User registration.
- User login.
- Firebase Authentication.
- Store user profile in Firestore.
- Display current user information.
- Update profile information.
- Display a list of users where permitted by Security Rules.
- Delete a user profile document where permitted.
- Logout.
- Loading and error states.
Suggested Firestore Structure
users
|
+-- USER_UID
|
+-- name
+-- email
+-- phone
+-- createdAt
+-- profileImage
78. Mini Project: Product Management App
Create a product management application using Cloud Firestore.
Features
- Search or filter products using supported queries.
- Use Security Rules to restrict write access.
79. Interview Questions
- What is Cloud Firestore?
- What is the difference between a collection and a document?
- What is a Firestore document ID?
- What are Firestore subcollections?
- How do you add Cloud Firestore to a Flutter project?
- What is
FirebaseFirestore.instance?
- What is the difference between
add() and set()?
- What is the difference between
set() and update()?
- How do you retrieve a single Firestore document?
- How do you retrieve all documents from a collection?
- What is the difference between
get() and snapshots()?
- How do you display real-time Firestore data in Flutter?
- How does
StreamBuilder work with Firestore?
- How do you filter Firestore documents?
- What is
where()?
- What is
orderBy()?
- What is
limit()?
- What are Firestore indexes?
- What are Firestore Security Rules?
- How do Firebase Authentication and Firestore work together?
- Why is a user's Firebase UID useful in Firestore?
- What is offline support in Firestore?
- What are Firestore transactions?
- What are batch writes?
- How can Firestore data be converted into Dart model classes?
80. Quick Revision
| Concept |
Important API |
| Firestore Instance |
FirebaseFirestore.instance |
| Collection |
collection() |
| Document |
doc() |
| Create with Auto ID |
add() |
| Create/Replace |
set() |
| Update |
update() |
| Read Once |
get() |
| Real-Time Data |
snapshots() |
| Filter |
where() |
| Sort |
orderBy() |
| Limit |
limit() |
| Delete |
delete() |
| Server Timestamp |
FieldValue.serverTimestamp() |
| Increment |
FieldValue.increment() |
| Array Add |
FieldValue.arrayUnion() |
| Array Remove |
FieldValue.arrayRemove() |
| Transaction |
runTransaction() |
| Batch Write |
batch() |
81. Learning Outcomes
After completing this topic, you should be able to:
- Explain Cloud Firestore and its NoSQL data model.
- Understand collections, documents, fields, and subcollections.
- Configure Cloud Firestore in a Flutter application.
- Add documents with automatic and custom IDs.
- Read individual and multiple documents.
- Update and delete Firestore data.
- Filter and sort Firestore data.
- Display Firestore data using FutureBuilder.
- Display real-time Firestore data using StreamBuilder.
- Use timestamps and atomic field operations.
- Work with nested data and subcollections.
- Use Firestore with Firebase Authentication.
- Understand Firestore Security Rules.
- Handle loading, error, empty, and success states.
- Use Dart models and service classes for scalable applications.
- Understand transactions, batch writes, pagination, and offline support.
82. Official Firebase Resources
83. JustAcademy Flutter Resources
For structured Flutter learning, practical development training, and additional Flutter topics, explore the following resources:
84. Summary
Cloud Firestore is a flexible NoSQL cloud database that stores data using collections and documents. Flutter applications can use the Cloud Firestore Flutter plugin to create, read, update, delete, query, and listen to application data.
Firestore can be combined with Firebase Authentication to create user-specific data structures, while Security Rules help control access to documents. Real-time listeners make Firestore useful for applications such as chat systems and live dashboards, while queries, indexes, transactions, batch writes, and offline support provide additional capabilities for building more advanced applications.