Firestore Subcollections In Flutter
Firebase is an amazing platform developed by Google to connect mobile and web applications and help developers to improve, build, and grow their apps. Firebase provides us a variety of products Authentication, Realtime Database, Cloud Firestore, Cloud Storage, Cloud Functions, Firebase Hosting, ML Kit. Firebase is highly effective and easy to use.
Firebase cloud firestore is a flexible and scalable database. It offers offline availability of data across your client’s apps and keeps data in-sync across clients apps through realtime listeners.
In this blog, we shall discuss how to work with cloud firestore subcollections:
Table of contents:
::Connecting app to your firebase project
To work with firebase cloud firestore in flutter you need to learn about basic crud operation i.e. uploading data, deleting data, editing data, fetching data.
Using Firebase Firestore in Flutter
Fetching data from cloud firestoremedium.com
What is subcollection?
Let’s understand subcollection through an example, take an example of a shopping application, in this app, there are two people 1st the user that will place the order and the 2nd wander that will accept the user’s orders. For each user, the wander needs to keep a record of every user’s order. So to keep the data in a sequential manner we can create a subcollection in the following manner.
In the above image, you can easily analyze the user’s order in an easier and precise manner. So to create this type of collection we need to specify the documentId
.
Why the documentId
is important?
Assigning a specific documentId
is very important if you are building two different applications one for the user and the other for a wander. To fetch all the orders with the user’s details we need to get all the documentId
of all orders placed by different users inside our wanders application. So to get that documentId
we need to fetch it from the users
collection that I have created.
Let me explain to you the whole cycle of getting that documentId
:
- At the time of user authentication a
userId
is generated by the firebase, we will use this userId and upload it along with user information on cloud firestore inside ausers
collection.
await FirebaseFirestore.instance
.collection('users')
.doc(userCredential.user.uid)
.set({
'username': username,
'email': email,
'laundryBagNo': laundryBagNo,
'image_url': url,
'userId': userCredential.user.uid //this_one
});
2. Now in the other application we will fetch the stream of users
and using the snapshot of the stream we will get all the userId i.e.
‘userId’: userCredential.user.uid //this_one
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('users').snapshots(),
builder: (context, userSnapshot) {
return userSnapshot.hasData
? ListView.builder(
itemCount: userSnapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot userData =
userSnapshot.data.documents[index];
if (userData
.data()['laundryBagNo']
.toString()
.startsWith('B-') &&
boys)
return UserCard(
userId: userData.data()['userId'],
userEmail: userData.data()['email'],
userName: userData.data()['username'],
userLaundryBagNo:
userData.data()['laundryBagNo'],
userImageUrl: userData.data()['image_url']);
else if (userData
.data()['laundryBagNo']
.toString()
.startsWith('G-') &&
girls)
return UserCard(
userId: userData.data()['userId'],
userEmail: userData.data()['email'],
userName: userData.data()['username'],
userLaundryBagNo:
userData.data()['laundryBagNo'],
userImageUrl: userData.data()['image_url']);
else
return SizedBox();
})
: CircularProgressIndicator();
},
),
Now we can access the subcollection that we have created named order
and we use this id to get all the users and orders.
Connecting app to your firebase project:
If you are new to firebase then you can follow the steps that I have mentioned in my crud operation blog to connect your apps to Firebase, you can add more then one app to your firebase project:
Using Firebase Firestore in Flutter
Fetching data from cloud firestoremedium.com
Creating users collection:
As we have discussed above, we need a users
collection that will store the userId and other users information. We will create this collection when the user signs up.
await FirebaseFirestore.instance
.collection('users')
.doc(userCredential.user.uid)
.set({
'username': username,
'email': email,
'laundryBagNo': laundryBagNo,
'image_url': url,
'userId': userCredential.user.uid
});
Here users
is a collection that contains a document whose id is userId i.e. userCredential.user.uid
.
Creating a sub-collection:
orders
is a collection that contains a document whose id is the userId that we can easily get through FirebaseAuth instance using currentUser.
User user = FirebaseAuth.instance.currentUser;
, inside this document, we will create another collection user_orders
. user_orders
is our sub-collection.
await FirebaseFirestore
.instance
.collection('orders')
.doc(user.uid)
.collection(
"user_orders")
.add({
//add your data that you want to upload
});
Fetching a sub-collection:
To fetch orders
subcollection we will need the documentId
, so to get the documentId we need to fetch the users
collection to get the userId
.
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('users').snapshots(),
builder: (context, userSnapshot) {
return userSnapshot.hasData
? ListView.builder(
itemCount: userSnapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot userData =
userSnapshot.data.documents[index];
if (userData
.data()['laundryBagNo']
.toString()
.startsWith('B-') &&
boys)
return UserCard(
userId: userData.data()['userId'],
userEmail: userData.data()['email'],
userName: userData.data()['username'],
userLaundryBagNo:
userData.data()['laundryBagNo'],
userImageUrl: userData.data()['image_url']);
else if (userData
.data()['laundryBagNo']
.toString()
.startsWith('G-') &&
girls)
return UserCard(
userId: userData.data()['userId'],
userEmail: userData.data()['email'],
userName: userData.data()['username'],
userLaundryBagNo:
userData.data()['laundryBagNo'],
userImageUrl: userData.data()['image_url']);
else
return SizedBox();
})
: CircularProgressIndicator();
},
)
UserCard
is a widget that displays the user details and on taping it new screen is pushed that contains all the orders of that particular user.
Now we will use the userId
to fetch the sub-collection.
class CurrentOrders extends StatelessWidget {
final String userId;
CurrentOrders({
@required this.userId,
});
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('orders')
.doc(userId)
.collection('user_orders')
.snapshots(),
builder: (context, orderSnapshot) {
return orderSnapshot.hasData
? ListView.builder(
itemCount: orderSnapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot orderData =
orderSnapshot.data.documents[index];
return OrderItem();
},
)
: CircularProgressIndicator();
});
}
}
Updating sub-collection:
FirebaseFirestore.instance
.collection('orders')
.doc(userId)
.collection('user_orders')
.doc(orderData.id)
.update(
{'key': 'new_value'});
Deleting sub-collection:
FirebaseFirestore.instance
.collection('orders')
.doc(userId)
.collection('user_orders')
.doc(orderData.id)
.delete();
Thanks for reading this article ❤
If I got something wrong? Let me know in the comments. I would love to improve.
Clap 👏 If this article helps you.
If we got something wrong? Let me know in the comments. we would love to improve.
Feel free to connect with us:
And read more articles from FlutterDevs.com
FlutterDevs team of Flutter developers to build high-quality and functionally-rich apps. Hire a flutter developer for your cross-platform Flutter mobile app project on an hourly or full-time basis as per your requirement! You can connect with us on Facebook, GitHub, and Twitter for any flutter related queries.
We welcome feedback and hope that you share what you’re working on using #Flutter. We truly enjoy seeing how you use Flutter to build beautiful, interactive web experiences!
Thank you for reading. 🌸