Storing and Retrieving Application Data in Flutter
Storing and retrieving application data is an essential part of Flutter application development. Most real-world applications need to save information such as user profiles, products, orders, messages, tasks, settings, and other application data.
Flutter applications can work with different types of storage depending on the requirements. For cloud-based application data, Cloud Firestore is a popular Firebase solution. Firestore is a NoSQL document database that stores data in collections and documents and supports one-time reads, queries, real-time listeners, and offline capabilities.
1. What is Application Data?
Application data is information created, entered, or used by an application during its operation.
Examples include:
- User names and email addresses
For example, an e-commerce application may store products like this:
products
├── product001
│ ├── name: "Laptop"
│ ├── price: 65000
│ └── category: "Electronics"
└── product002
├── name: "Phone"
├── price: 35000
└── category: "Electronics"
2. Why Do Applications Need Data Storage?
Without persistent storage, information entered by users may disappear when the application is closed or the application state is recreated.
Data storage allows applications to:
- Retrieve previously stored information.
- Update existing information.
- Delete information when required.
- Synchronize information between devices.
- Provide personalized experiences.
- Maintain application state and records.
3. Types of Data Storage in Flutter
Different applications require different storage solutions.
| Storage Type |
Common Use |
| Shared Preferences |
Small key-value settings and preferences |
| SQLite |
Structured local relational data |
| Hive |
Local NoSQL-style storage |
| Secure Storage |
Sensitive local values such as tokens |
| Cloud Firestore |
Cloud-based NoSQL application data |
| Firebase Realtime Database |
Real-time JSON-based application data |
This topic focuses primarily on storing and retrieving application data using Cloud Firestore with Flutter.
4. What is Cloud Firestore?
Cloud Firestore is a flexible, scalable NoSQL document database provided by Firebase. It stores data in documents organized into collections. Documents can contain fields, nested objects, and subcollections.
Firestore also supports queries, real-time listeners, and offline capabilities on supported platforms.
Cloud Firestore Documentation
5. Firestore Data Model
Firestore uses a collection and document structure rather than traditional SQL tables and rows.
Firestore
|
+-- Collection
|
+-- Document
|
+-- Fields
|
+-- Subcollections
Example
users
|
+-- user001
|
+-- name: "John Doe"
+-- email: "[email protected]"
+-- age: 25
+-- isActive: true
6. Collections
A collection is a group of related documents.
Examples:
users
products
orders
messages
courses
tasks
A collection can contain many documents.
7. Documents
A document is a record containing fields and values.
users
|
+-- user001
|
+-- name: "John Doe"
+-- email: "[email protected]"
+-- age: 25
Every document has an identifier. Firestore can generate an ID automatically, or your application can specify one.
8. Fields
Fields contain the actual data stored inside a document.
| Field |
Example |
Type |
| name |
John Doe |
String |
| age |
25 |
Number |
| isActive |
true |
Boolean |
| skills |
["Flutter","Dart"] |
Array |
| address |
{city: "Mumbai"} |
Map |
| createdAt |
Timestamp |
Timestamp |
9. Prerequisites
Before storing and retrieving application data with Cloud Firestore, you should have:
- Firebase configured with the Flutter application.
- Cloud Firestore enabled in Firebase Console.
For Firebase configuration, follow the official Flutter setup documentation.
Firebase Setup for Flutter
10. Add Cloud Firestore to Flutter
Add the Cloud Firestore Flutter plugin using:
flutter pub add cloud_firestore
Then import it into the Dart file:
import 'package:cloud_firestore/cloud_firestore.dart';
11. Access Firestore
The Firestore instance can be accessed using FirebaseFirestore.instance.
final db = FirebaseFirestore.instance;
You can then use the instance to access collections and documents.
12. Firebase Initialization
Firebase must be initialized before Firestore operations are performed.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
In a FlutterFire-configured application, Firebase is commonly initialized using generated configuration options.
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
13. Storing Application Data
Storing data means writing information from the Flutter application into a database.
Firestore provides methods such as:
14. Store Data with add()
The add() method creates a new document with an automatically generated document ID.
await FirebaseFirestore.instance
.collection('users')
.add({
'name': 'John Doe',
'email': '[email protected]',
'age': 25,
});
Firestore generates a unique document ID for the new document.
15. Store Data with a Custom Document ID
Use doc() and set() 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 resulting structure is:
users
|
+-- user001
|
+-- name: John Doe
+-- email: [email protected]
+-- age: 25
16. Storing Different Data Types
Firestore documents can contain different types of values.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'age': 25,
'isActive': true,
'skills': ['Flutter', 'Dart', 'Firebase'],
'address': {
'city': 'Mumbai',
'country': 'India',
},
});
17. Store Date and Time
Firestore supports timestamp values.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'createdAt': Timestamp.now(),
});
You can also use a server-side timestamp:
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'createdAt': FieldValue.serverTimestamp(),
});
18. Store Application Data from a Form
A common Flutter pattern is collecting information from a form and storing it in Firestore.
Controllers
final nameController = TextEditingController();
final emailController = TextEditingController();
Save Function
Future saveUser() async {
final name = nameController.text.trim();
final email = emailController.text.trim();
await FirebaseFirestore.instance
.collection('users')
.add({
'name': name,
'email': email,
'createdAt': FieldValue.serverTimestamp(),
});
}
Save Button
ElevatedButton(
onPressed: saveUser,
child: const Text('Save'),
)
19. Form Validation Before Storing Data
Always validate important user input before storing it.
Future saveUser() async {
final name = nameController.text.trim();
final email = emailController.text.trim();
if (name.isEmpty || email.isEmpty) {
return;
}
await FirebaseFirestore.instance
.collection('users')
.add({
'name': name,
'email': email,
});
}
For larger forms, Flutter's Form and TextFormField widgets can be used for structured validation.
20. Retrieve 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());
}
The retrieved document contains its fields and values.
21. Retrieve Document Data
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
if (doc.exists) {
final data = doc.data();
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 found');
} else {
print('Document not found');
}
23. Retrieve All Documents
Use get() on a collection reference to retrieve multiple documents.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
for (final doc in snapshot.docs) {
print('ID: ${doc.id}');
print('Data: ${doc.data()}');
}
24. Retrieve Data as a List
Firestore query results can be converted into a list that can be displayed in Flutter.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
final users = snapshot.docs.map((doc) {
return {
'id': doc.id,
...doc.data(),
};
}).toList();
25. Display Stored Data in ListView
Firestore data can be displayed using Flutter's ListView.builder.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
final users = snapshot.docs;
ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index].data();
return ListTile(
title: Text(user['name'] ?? ''),
subtitle: Text(user['email'] ?? ''),
);
},
)
26. FutureBuilder for Retrieving Data
FutureBuilder is useful when retrieving Firestore data once and displaying the result in the Flutter UI.
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('Unable to load data'),
);
}
if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
return const Center(
child: Text('No data 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 Data Retrieval
Cloud Firestore supports real-time listeners. Instead of retrieving data only once, an application can listen for changes and update the UI when the listened-to data changes.
FirebaseFirestore.instance
.collection('users')
.snapshots()
.listen((snapshot) {
for (final doc in snapshot.docs) {
print(doc.data());
}
});
28. StreamBuilder for Real-Time Data
StreamBuilder can automatically rebuild the Flutter 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 data'),
);
}
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. Difference Between get() and snapshots()
| Feature |
get() |
snapshots() |
| Purpose |
Retrieve data once |
Listen for data changes |
| Return Type |
Future |
Stream |
| Typical Widget |
FutureBuilder |
StreamBuilder |
| Real-Time Updates |
No continuous listener |
Yes |
| Common Use |
One-time data loading |
Live data screens |
30. Retrieve Data Using Queries
Firestore queries allow the application to retrieve only documents that match specific conditions.
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where(
'isActive',
isEqualTo: true,
)
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
31. Retrieve Data by Email
final snapshot = await FirebaseFirestore.instance
.collection('users')
.where(
'email',
isEqualTo: '[email protected]',
)
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
32. Retrieve Data by Category
final snapshot = await FirebaseFirestore.instance
.collection('products')
.where(
'category',
isEqualTo: 'Electronics',
)
.get();
33. Retrieve Data Using Multiple Conditions
Firestore supports compound queries when the selected query structure is supported.
final snapshot = await FirebaseFirestore.instance
.collection('products')
.where(
'category',
isEqualTo: 'Electronics',
)
.where(
'isAvailable',
isEqualTo: true,
)
.get();
34. Sort Retrieved Data
The orderBy() method can be used to specify the sort order.
final snapshot = await FirebaseFirestore.instance
.collection('products')
.orderBy('price')
.get();
Descending Order
final snapshot = await FirebaseFirestore.instance
.collection('products')
.orderBy(
'price',
descending: true,
)
.get();
35. Limit Retrieved Data
The limit() method restricts the number of documents returned.
final snapshot = await FirebaseFirestore.instance
.collection('products')
.limit(10)
.get();
Limiting data is useful when the application does not need to retrieve an entire collection at once.
36. Store and Retrieve Product Data
Store Product
await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.set({
'name': 'Laptop',
'price': 65000,
'category': 'Electronics',
'isAvailable': true,
});
Retrieve Product
final doc = await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.get();
if (doc.exists) {
final product = doc.data();
print(product?['name']);
print(product?['price']);
}
37. Updating Stored Data
Application data often needs to be modified after it has been stored.
Use update() to modify selected fields.
await FirebaseFirestore.instance
.collection('products')
.doc('product001')
.update({
'price': 62000,
});
38. Update Multiple Fields
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'name': 'John Smith',
'age': 26,
'isActive': true,
});
39. Delete Stored Data
Use delete() to remove a document.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.delete();
40. CRUD Operations
CRUD represents the four basic database operations:
| Operation |
Firestore Method |
Purpose |
| Create |
add() / set() |
Store new data |
| Read |
get() / snapshots() |
Retrieve data |
| Update |
update() |
Modify existing data |
| Delete |
delete() |
Remove data |
41. Storing User Data with Firebase Authentication
Cloud Firestore is commonly used with Firebase Authentication. Authentication identifies the user, while Firestore stores additional application-specific user information.
A common structure is:
users
|
+-- USER_UID
|
+-- name
+-- email
+-- phone
+-- createdAt
Example
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.set({
'name': 'John Doe',
'email': user.email,
'createdAt': FieldValue.serverTimestamp(),
});
}
42. Retrieve Current User Data
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
final doc = await FirebaseFirestore.instance
.collection('users')
.doc(user.uid)
.get();
if (doc.exists) {
final data = doc.data();
print(data?['name']);
print(data?['email']);
}
}
43. Store Nested Data
Firestore documents can contain nested maps.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'address': {
'city': 'Mumbai',
'state': 'Maharashtra',
'country': 'India',
},
});
44. Retrieve Nested Data
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
final data = doc.data();
if (data != null) {
final address = data['address'];
print(address['city']);
print(address['state']);
}
45. Store Data in Subcollections
Subcollections can be used when data belongs to a particular document.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.collection('orders')
.doc('order001')
.set({
'product': 'Flutter Course',
'price': 5000,
'status': 'completed',
});
The structure becomes:
users
|
+-- user001
|
+-- orders
|
+-- order001
|
+-- product
+-- price
+-- status
46. Retrieve Subcollection Data
final snapshot = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.collection('orders')
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
47. Convert Firestore Data into Dart Models
For small applications, working directly with maps may be sufficient. For larger applications, Dart model classes provide a cleaner and more maintainable approach.
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'] ?? '',
);
}
}
48. Retrieve Data Using a 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);
}
49. Store Data Using a Model
A model can also provide a method for converting Dart objects into Firestore-compatible maps.
class UserModel {
final String id;
final String name;
final String email;
UserModel({
required this.id,
required this.name,
required this.email,
});
Map toFirestore() {
return {
'name': name,
'email': email,
};
}
}
Save Model
final user = UserModel(
id: 'user001',
name: 'John Doe',
email: '[email protected]',
);
await FirebaseFirestore.instance
.collection('users')
.doc(user.id)
.set(user.toFirestore());
50. Firestore Service Class
Database operations can be moved into a separate service class.
class UserService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
Future createUser({
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();
}
}
51. Loading State
Database operations are asynchronous, so the UI should display a loading indicator while data is being retrieved.
bool isLoading = false;
Future loadUsers() async {
setState(() {
isLoading = true;
});
try {
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
// Process data
} finally {
if (mounted) {
setState(() {
isLoading = false;
});
}
}
}
52. Error Handling
Firestore operations can fail because of network problems, permission errors, invalid queries, or other conditions. Always handle possible errors.
try {
final snapshot = await FirebaseFirestore.instance
.collection('users')
.get();
print(snapshot.docs);
} on FirebaseException catch (e) {
print('Firestore error: ${e.code}');
print('Message: ${e.message}');
} catch (e) {
print('Unexpected error: $e');
}
53. Empty State
An application should handle the case where no documents are returned.
if (snapshot.docs.isEmpty) {
return const Center(
child: Text('No data available'),
);
}
Empty-state messages provide useful feedback instead of displaying a blank screen.
54. Complete Data State Flow
Request Data
|
v
Loading
|
v
Firestore Request
|
+---- Error ----> Error State
|
+---- No Data --> Empty State
|
+---- Data ----> Success State
|
v
Display Data
55. Real-Time User List Example
class UsersScreen extends StatelessWidget {
const UsersScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Users'),
),
body: StreamBuilder<
QuerySnapshot>>(
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('Unable to load 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'] ?? ''),
);
},
);
},
),
);
}
}
56. Storing Application Settings
Firestore can also store settings that need to be available across devices.
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'settings': {
'darkMode': true,
'notifications': true,
'language': 'English',
},
}, SetOptions(merge: true));
57. Retrieve Application Settings
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
final data = doc.data();
if (data != null) {
final settings = data['settings'];
print(settings['darkMode']);
print(settings['notifications']);
print(settings['language']);
}
58. Storing Orders
An e-commerce application can store order information in Firestore.
await FirebaseFirestore.instance
.collection('orders')
.add({
'userId': 'user001',
'productId': 'product001',
'quantity': 2,
'totalAmount': 130000,
'status': 'pending',
'createdAt': FieldValue.serverTimestamp(),
});
59. Retrieve Orders for a User
final snapshot = await FirebaseFirestore.instance
.collection('orders')
.where(
'userId',
isEqualTo: 'user001',
)
.get();
for (final doc in snapshot.docs) {
print(doc.data());
}
60. Store Messages
Firestore can be used to store messages for chat or communication features.
await FirebaseFirestore.instance
.collection('messages')
.add({
'senderId': 'user001',
'message': 'Hello!',
'createdAt': FieldValue.serverTimestamp(),
});
61. Retrieve Messages in Real Time
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['message'] ?? ''),
subtitle: Text(message['senderId'] ?? ''),
);
},
);
},
)
62. Pagination
When a collection contains a large number of documents, retrieving everything at once may not be appropriate. Firestore supports query cursors that can be used to retrieve data in pages.
A typical pagination flow is:
First Request
|
v
Load First Page
|
v
Remember Last Document
|
v
Request Next Page
|
v
Append New Data
|
v
Continue Until No More Data
Pagination should be designed together with appropriate ordering and filtering.
63. Limit and Order Data for Pagination
final snapshot = await FirebaseFirestore.instance
.collection('products')
.orderBy('createdAt', descending: true)
.limit(10)
.get();
The last document from one query can be used as a cursor for a subsequent query when implementing cursor-based pagination.
64. Offline Data
Cloud Firestore provides offline capabilities on supported client platforms. Firestore can cache data that the application is actively using and synchronize local changes with the backend when connectivity returns.
This can help applications remain responsive when network connectivity is temporarily unavailable.
Firestore Offline Data Documentation
65. Firestore Security Rules
Application data should not be left publicly accessible in production. Firestore Security Rules can be used to control access to documents and collections.
For example, a user-specific document can be protected using the authenticated user's UID.
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 rule allows an authenticated user to access the user document whose document ID matches their Firebase Authentication UID.
66. Security and Data Validation
- Use Firebase Authentication when user identity is required.
- Protect Firestore data with Security Rules.
- Do not store sensitive information unnecessarily.
- Validate important data before storing it.
- Use UID-based document structures for user-specific data.
- Design queries that are compatible with your Security Rules.
- Do not assume client-side validation is sufficient for database security.
- Review Security Rules before deploying the application.
67. Firestore Data Architecture
A clean application architecture can separate the UI, business logic, and database operations.
Flutter UI
|
v
Controller / ViewModel
|
v
Repository / Service
|
v
Cloud Firestore
|
v
Firebase Backend
This approach makes the application easier to maintain and test.
68. Recommended Project Structure
lib/
├── main.dart
├── firebase_options.dart
├── models/
│ ├── user_model.dart
│ ├── product_model.dart
│ └── order_model.dart
├── services/
│ ├── firestore_service.dart
│ └── auth_service.dart
├── repositories/
│ └── user_repository.dart
├── screens/
│ ├── home_screen.dart
│ ├── users_screen.dart
│ ├── products_screen.dart
│ └── orders_screen.dart
└── widgets/
├── user_card.dart
├── product_card.dart
└── loading_widget.dart
69. Common Mistakes
| Mistake |
Better Approach |
| Loading all documents unnecessarily |
Use queries, limits, and pagination where appropriate. |
| Ignoring errors |
Handle Firestore exceptions. |
| Ignoring empty results |
Display an appropriate empty state. |
| No loading indicator |
Show loading feedback during asynchronous operations. |
| Public database rules in production |
Use appropriate Security Rules. |
| Mixing database code with every widget |
Use services or repositories. |
| Using raw maps everywhere |
Use Dart model classes for larger applications. |
| Retrieving data repeatedly |
Use appropriate state management and listeners. |
| Ignoring query limitations |
Design supported queries and indexes carefully. |
70. Best Practices
- Design your Firestore data structure before writing application code.
- Use meaningful collection and document names.
- Use model classes for complex applications.
- Separate Firestore operations from UI widgets.
- Handle loading, success, error, and empty states.
- Use queries instead of downloading unnecessary data.
- Use
limit() and pagination for large datasets.
- Use real-time listeners only where real-time updates are required.
- Use server timestamps for server-generated timestamps when appropriate.
- Protect data using Firebase Authentication and Security Rules.
- Test Firestore Security Rules before production.
- Keep sensitive information out of client-side code.
- Use offline support thoughtfully when your application requires it.
71. Complete CRUD Example
Create
Future createUser() async {
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.set({
'name': 'John Doe',
'email': '[email protected]',
'createdAt': FieldValue.serverTimestamp(),
});
}
Read
Future readUser() async {
final doc = await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.get();
print(doc.data());
}
Update
Future updateUser() async {
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.update({
'name': 'John Smith',
});
}
Delete
Future deleteUser() async {
await FirebaseFirestore.instance
.collection('users')
.doc('user001')
.delete();
}
72. Mini Project: User Data Management App
Create a Flutter application that stores and retrieves user information using Cloud Firestore.
Features
- View individual user details.
- Use Firebase Authentication for user identity.
- Protect data with Firestore Security Rules.
Suggested Firestore Structure
users
|
+-- USER_UID
|
+-- name
+-- email
+-- phone
+-- createdAt
+-- updatedAt
73. Mini Project: Product Management App
Create a product management application that uses Firestore as its cloud database.
Product Structure
products
|
+-- product001
|
+-- name
+-- price
+-- category
+-- description
+-- isAvailable
+-- createdAt
Required Operations
- Add product.
- Display products.
- Search or filter products.
- Sort products by price.
- Update product.
- Delete product.
- Display loading state.
- Handle errors.
- Handle empty results.
74. Interview Questions
- What is application data?
- Why do Flutter applications need persistent storage?
- What is Cloud Firestore?
- What is the Firestore data model?
- What is a collection?
- What is a document?
- What are Firestore fields?
- How do you add Cloud Firestore to a Flutter application?
- What is
FirebaseFirestore.instance?
- What is the difference between
add() and set()?
- How do you store data with a custom document ID?
- How do you retrieve a single document?
- How do you retrieve all documents from a collection?
- What is the difference between
get() and snapshots()?
- How do you display Firestore data using
FutureBuilder?
- How do you display real-time data using
StreamBuilder?
- How do you filter Firestore data?
- What is
where()?
- What is
orderBy()?
- What is
limit()?
- How do you update a Firestore document?
- How do you delete a Firestore document?
- How do Firebase Authentication and Firestore work together?
- What are Firestore Security Rules?
- Why should model classes be used in larger applications?
- What is a Firestore subcollection?
- What is real-time data retrieval?
- What is offline support in Firestore?
75. Quick Revision
| Concept |
Firestore API |
| Firestore Instance |
FirebaseFirestore.instance |
| Collection |
collection() |
| Document |
doc() |
| Store with Auto ID |
add() |
| Store with Custom ID |
set() |
| Update Data |
update() |
| Retrieve Once |
get() |
| Real-Time Retrieval |
snapshots() |
| Filter Data |
where() |
| Sort Data |
orderBy() |
| Limit Data |
limit() |
| Delete Data |
delete() |
| Server Timestamp |
FieldValue.serverTimestamp() |
| Increment Value |
FieldValue.increment() |
| Array Add |
FieldValue.arrayUnion() |
| Array Remove |
FieldValue.arrayRemove() |
76. Learning Outcomes
After completing this topic, you should be able to:
- Explain application data and persistent storage.
- Understand the Cloud Firestore data model.
- Configure Firestore in a Flutter application.
- Retrieve individual documents.
- Retrieve multiple documents.
- Update stored application data.
- Filter and sort retrieved data.
- Display Firestore data using Flutter widgets.
- Use FutureBuilder for one-time data retrieval.
- Use StreamBuilder for real-time data.
- Store nested data and subcollections.
- Connect Firestore with Firebase Authentication.
- Convert Firestore documents into Dart models.
- Create Firestore service classes.
- Handle loading, error, empty, and success states.
- Apply Firestore Security Rules.
- Understand pagination and offline data concepts.
77. Official Firebase Resources
78. JustAcademy Flutter Resources
For structured Flutter learning, practical development training, and additional Flutter topics, explore the following resources:
79. Summary
Storing and retrieving application data is a fundamental requirement for real-world Flutter applications. Cloud Firestore provides a flexible NoSQL database where application data can be organized into collections and documents.
Flutter applications can use Firestore to create, read, update, delete, query, and listen to application data in real time. One-time reads can be performed with get(), while real-time updates can be handled with snapshots(). Queries such as where(), orderBy(), and limit() help retrieve the required data efficiently.
For production applications, Firestore should be combined with proper data modeling, loading and error handling, Firebase Authentication where appropriate, Security Rules, and a clean service or repository architecture.