Flutter Firebase Firestore CRUD | Create | Update | Delete | Real Time Database

Flutter Firebase Firestore CRUD | Create | Update | Delete | Real Time Database

    We will fully understand how firebase firestore CRUD operations work and what collections and documents mean.

    Flutter firebase image upload

    Once you create Firebase project, you will need to create database using Firestore database. In Firestore, database objects are refered as document and collection.

    Collection is more like a table like in MySQL..

    Document refers to the rows like in MySQL.. 

    So first we need to create a instance of our table using below line

      final CollectionReference _products =
          FirebaseFirestore.instance.collection('products');

    Now if you have multiple tables then you would create multiple references using the code like above.

    Anyway, we would be able to do further operations on table products using _products instance.

    Now let's take a look how we will do CRUD operations on the table products using _products. We will have below three lines of code. 

    And they are the heart of firebase operations.

    await _products.add({"name": name, "price": price});
    await _products.update({"name": name, "price": price});
    await _products.doc(productId).delete();

    We will create connection to the Firestore using StreamBuilder.

    StreamBuilder(
            stream: _products.snapshots(), //build connection
            builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
              if (streamSnapshot.hasData) {
                return ListView.builder(
                  itemCount: streamSnapshot.data!.docs.length,  //number of rows
                  itemBuilder: (context, index) {
                    final DocumentSnapshot documentSnapshot =
                        streamSnapshot.data!.docs[index];
                    return Card(
                      margin: const EdgeInsets.all(10),
                      child: ListTile(
                        title: Text(documentSnapshot['name']),
                        subtitle: Text(documentSnapshot['price'].toString()),
                        trailing: SizedBox(
                          width: 100,
                          child: Row(
                            children: [
    // Press this button to edit a single product
                              IconButton(
                                  icon: const Icon(Icons.edit),
                                  onPressed: () =>
                                      _update(documentSnapshot)),
    // This icon button is used to delete a single product
                              IconButton(
                                  icon: const Icon(Icons.delete),
                                  onPressed: () =>
                                      _deleteProduct(documentSnapshot.id)),
                            ],
                          ),
                        ),
                      ),
                    );
                  },
                );
              }
    
              return const Center(
                child: CircularProgressIndicator(),
              );
            },
          )

    In the above code _prodcuts.snapshots(), refers to the rows or the documents and stream of firestore data source.

    And we use  AsyncSnapshot<QuerySnapshot> streamSnapshot to get the actual data. So the rows could be accessed by using streamSnapshot.data

    So streamSnapshot.data.docs would refer to the rows of the database. Once again in Firestore documents are equivalent to rows of MySQL

    You might be interested in learning about

    1. E-commerce app with paypal payment and backend (Getx sate management)
    2. Travel app with backend (BLoC state management)
    3. Study app with Firebase backend (Getx state management)
    4. Educational course selling app with stripe payment (BLoC state management)
    5. Complete Firebase chat app
    6. Audio Video and Text Chat app with Laravel
    7. Flutter game app

    The complete code

    
    import 'package:flutter/material.dart';
    import 'package:firebase_core/firebase_core.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Firebase Firestore',
          home: HomePage(),
        );
      }
    }
    
    class HomePage extends StatefulWidget {
      const HomePage({Key? key}) : super(key: key);
    
      @override
      _HomePageState createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
    // text fields' controllers
      final TextEditingController _nameController = TextEditingController();
      final TextEditingController _priceController = TextEditingController();
    
      final CollectionReference _products =
          FirebaseFirestore.instance.collection('products');
    
      Future<void> _create([DocumentSnapshot? documentSnapshot]) async {
    
        await showModalBottomSheet(
            isScrollControlled: true,
            context: context,
            builder: (BuildContext ctx) {
              return Padding(
                padding: EdgeInsets.only(
                    top: 20,
                    left: 20,
                    right: 20,
                    bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    TextField(
                      controller: _nameController,
                      decoration: const InputDecoration(labelText: 'Name'),
                    ),
                    TextField(
                      keyboardType:
                      const TextInputType.numberWithOptions(decimal: true),
                      controller: _priceController,
                      decoration: const InputDecoration(
                        labelText: 'Price',
                      ),
                    ),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      child: const Text('Create'),
                      onPressed: () async {
                        final String name = _nameController.text;
                        final double? price =
                        double.tryParse(_priceController.text);
                        if (price != null) {
                            await _products.add({"name": name, "price": price});
    
                          _nameController.text = '';
                          _priceController.text = '';
                            Navigator.of(context).pop();
                        }
                      },
                    )
                  ],
                ),
              );
    
            });
      }
      Future<void> _update([DocumentSnapshot? documentSnapshot]) async {
        if (documentSnapshot != null) {
    
          _nameController.text = documentSnapshot['name'];
          _priceController.text = documentSnapshot['price'].toString();
        }
    
        await showModalBottomSheet(
            isScrollControlled: true,
            context: context,
            builder: (BuildContext ctx) {
              return Padding(
                padding: EdgeInsets.only(
                    top: 20,
                    left: 20,
                    right: 20,
                    bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    TextField(
                      controller: _nameController,
                      decoration: const InputDecoration(labelText: 'Name'),
                    ),
                    TextField(
                      keyboardType:
                          const TextInputType.numberWithOptions(decimal: true),
                      controller: _priceController,
                      decoration: const InputDecoration(
                        labelText: 'Price',
                      ),
                    ),
                    const SizedBox(
                      height: 20,
                    ),
                    ElevatedButton(
                      child: const Text( 'Update'),
                      onPressed: () async {
                        final String name = _nameController.text;
                        final double? price =
                            double.tryParse(_priceController.text);
                        if (price != null) {
    
                            await _products
                                .doc(documentSnapshot!.id)
                                .update({"name": name, "price": price});
                          _nameController.text = '';
                          _priceController.text = '';
                            Navigator.of(context).pop();
                        }
                      },
                    )
                  ],
                ),
              );
            });
      }
    
      Future<void> _delete(String productId) async {
        await _products.doc(productId).delete();
    
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
            content: Text('You have successfully deleted a product')));
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Center(child: Text('Firebase Firestore')),
          ),
          body: StreamBuilder(
            stream: _products.snapshots(),
            builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
              if (streamSnapshot.hasData) {
                return ListView.builder(
                  itemCount: streamSnapshot.data!.docs.length,
                  itemBuilder: (context, index) {
                    final DocumentSnapshot documentSnapshot =
                        streamSnapshot.data!.docs[index];
                    return Card(
                      margin: const EdgeInsets.all(10),
                      child: ListTile(
                        title: Text(documentSnapshot['name']),
                        subtitle: Text(documentSnapshot['price'].toString()),
                        trailing: SizedBox(
                          width: 100,
                          child: Row(
                            children: [
                              IconButton(
                                  icon: const Icon(Icons.edit),
                                  onPressed: () =>
                                      _update(documentSnapshot)),
                              IconButton(
                                  icon: const Icon(Icons.delete),
                                  onPressed: () =>
                                      _delete(documentSnapshot.id)),
                            ],
                          ),
                        ),
                      ),
                    );
                  },
                );
              }
    
              return const Center(
                child: CircularProgressIndicator(),
              );
            },
          ),
    // Add new product
          floatingActionButton: FloatingActionButton(
            onPressed: () => _create(),
            child: const Icon(Icons.add),
    
          ),
            floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat
        );
      }
    }
    

     

    Flutter E-commerce App

    Flutter 3.0 Master Class

    Courses


    Recommended posts


    Recent posts