How to Use Firestore To Persist Data in Flutter Apps
Tags: flutter, firestore, tutorial, android
Published: 2020-03-09 15:49:02

Hello there! The purpose of this arcticle is to be very objective and summarize all about how to access and make the most common queries to **Firestore** using **Flutter**, Google's Mobile App SDK.

# Table of Contents
 * [Basics](#basics)
 * [Getting data](#getting-data)
   - [Get a single document](#get-single-document)
   - [Get a whole collection](#get-whole-collection)
 * [Updating data](#update-data)
 * [Inserting data](#insert-data)


## Example database

To examplify our tutorial, I'm gonna introduce a sample database which contains a simple collection of cars:



![Example database containing data from cars](https://i.imgur.com/8WlOjwV.png)


# Basics <a name="basics"></a>

You should use *Firestore* object and call it's instance to access the database from Firestore:

```final Firestore database = Firestore.instance;```

Now, the **database** object will get you access to all collections inside your Firestore database. 


# Getting data <a name="getting-data"></a>

## Get a single document <a name="get-single-document"></a>
```
Future<DocumentSnapshot> car = 
    database.collection('cars')
    .document('D3idV9o7uWT4pWvby643')
    .get();
```
The code above use our **database** variable to access our collection of *cars*, by passing its identifier (the collection's name) as argument. Then, we access the document we want to get, passing its unique ID. 

This will return a **Future\<DocumentSnapshot\>**. A **DocumentSnapshot** encapsulates all data inside an element from a collection. I suggest that you read its **[documentation](https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/DocumentSnapshot)**. It will get you more comfortable on how to manipulate the data inside a *DocumentSnapshot*.

So, since you have a **Future** object, it means that the **DocumentSnapshot** inside it only will be returned some moment after the instruction is executed, but you don't know exactly when. To extract the *DocumentSnapshot* inside it, you can use **then** method:

```
car.then( (DocumentSnapshot carSnapshot) => { 
   /* insert here the code of what you want to do with the snapshot*/  
});
```

Let's say, for example, that you want to access and print the property *model* from the car:

```
car.then( (carSnapshot) => { 
   print(carSnapshot["model"]) 
});

/* output is: 
Honda Civic 2.0 LXR
*/
```

## Get a whole collection <a name="get-whole-collection"></a>

To get all snapshots from a collection:

```
Stream<QuerySnapshot> stream = database.collection("cars").snapshots();
```

This will return a **Stream** object. To iterate over the object you got to perform some operations with the data it contains, you may use a **StreamBuilder**. 
Let's say, for example, that you want to show the model and year from each car you have inside your cars collection, displaying it in your app's screen.

```
...
final Stream<QuerySnapshot> stream = database.collection("cars").snapshots();

@override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: stream,
      builder: (context, snapshot) {
        if (snapshot.hasError) return ErrorDialog("Error while trying to access car data");
        switch (snapshot.connectionState) {
          case ConnectionState.active:
            return Container(
              child: ListView(
                children: List.generate(snapshot.data.documents.length, (index) {
                    DocumentSnapshot currentDocument = snapshot.data.documents[index];
                    return Text(currentDocument["model"] + " " + currentDocument["year"])
              })));

          default: return Text("Loading data");
        }
      }
    );
  }
```

# How to update data <a name="update-data"></a> 

This is how you **update data from an document** inside our collection of cars:
```
Future<void> updateData = database
   .collection('cars')
   .document('D3idV9o7uWT4pWvby643')
   .updateData(
      {
      "year": 2020,
      "model": "Toyota Corolla XEI 2.0",
      "hasInsurance": true
      });
```
If you want to **update just one field**, the query is just the same. You just have to pass only the field you want to update. For example:

```
Future<void> updateOneField = database
   .collection('cars')
   .document('D3idV9o7uWT4pWvby643')
   .updateData(
      {
      "hasInsurance": false
      });
```

# How to insert data <a name="insert-data"></a>

Use *setData* method, which creates a new document by passing the ID you want the document to have.

```
Future<void> insertData = database
   .collection("cars")
   .document("nVnAIom5wFBPL4h88w7D")
   .setData(
     {
     "model": "Tesla Model X",
     "year": 2019,
     "hasInsurance": true
     });
```

This will create a new element inside our cars collection. Just remember that, if there is already a document with same ID, it will get overrided. So, it may be a good idea to check if there is already a document with the ID you want to create before using *setData*. 
For doing so, you just have to perform a get (which you already know how to do by now) passing the ID you want to check. Then, verify if it returned a snapshot by using **exists** method. For example:

```
final docSnapshot = await database.collection('cars').document('nVnAIom5wFBPL4h88w7D').get();
if ( !docSnapshot.exists) {
   // insert logic to add a new document goes here
}
```

That's it, folks! With what you learned, I'm sure you will be able to get a lot o stuff done with **Flutter** and **Firestore**. 

**Hope that helps!**