DEV Community

Cover image for Designing Data Models for Firebase
Abdul Malik
Abdul Malik

Posted on

Designing Data Models for Firebase

In this article we will be speaking about designing data models for Firebase to make it super easy to store and retrieve them.

When we design a data model in our application for any entity say, a person.

We build a class with its

  • Properties
  • A constructor to initialize the object
  • Its methods (if needed)

Lets look at an example below :

class Person{
  int id;
  String name;
  String phoneNumber;
  String address;

// I used named arguments for the constructor available in Dart
  Person({this.id,this.name,this.phoneNumber,this.address});
}

Okay, so that was a Data Model, but how does Firebase fit into this?

Storing data in Firestore

Cloud Firestore supports a variety of data types > for values: boolean, number, string, geo point, > binary blob, and timestamp. ~ Cloud Firestore

Great ! So Firestore supports a wide variety of data types, so all we need to do is to convert our object (of the Data Model) into something we can store in a Firestore document. The easiest Data Structure would be Maps.

Instead of creating this Map manually everytime we want to store the object, why not just create a method for it in the class itself?

Meme reference : OOP 100 [ignore this if you're not into memes boomer]

The method for that would look something like this.

class Person{
  int id;
  String name;
  String phoneNumber;
  String address;
  Person({this.id,this.name,this.phoneNumber,this.address});
    // Convert current object to a Map and return it
  Map<String,dynamic> toMap() {
    return {
      "id"         : id,
      "name"       : name,
      "phoneNumber": phoneNumber,
      "address"    : address,
    };
  }
}

Awesome ! now we can convert our "person" object to a Map by simply calling this method before sending the data.

lets see the code.

Lets say there is an object of the Person class called personObject.

Store the person object in a document, whose ID is same as the Person ID [Best Practice]

Firestore
.instance
.collection(personObject.id) //Using the persons ID
.add(personObject.toMap());  //Converted using toMap()

There you go, Stored in Firestore in a single neat line of code.

I want to take a second to explain why we used the personObject's id as the document ID. While fetching the document from Firestore, we don't need to ask for all the documents in that collection and than pick ours.

Instead, we can directly make a query or ask Firestore to return a document with this particular ID. This decreases your Firestore reads, and is helpful if your application is going to scale and have lots of users, since you have a cap of 50k reads per day for free. After that you pay, and trust me i've hit that limit lots of times by writing stupid queries.

Retrieving data from Firestore

Ok, now to the part of retrieving data from Firebase.

When you receive a Document from Firestore, it is a Map from which you have to extract data and create an existing object to use in your application.

For that we will include another Constructor called "FromMap()" to create the object.

Okay, so Dart has Named Constructors but i'm sure any other OOP language would have parameterized constructors so you can use them. This is how our data model will look finally.

class Person{
  int id;
  String name;
  String phoneNumber;
  String address;
  Person({this.id,this.name,this.phoneNumber,this.address});
    // This is the named Constructor
  Person.fromMap(Map<String,dynamic> data){
    id          = data["id"];
    name        = data["name"];
    phoneNumber = data["phoneNumber"];
    address     = data["address"];
  }
    // I know i prob have OCD
  Map<String,dynamic> toMap() {
    return {
      "id"          : id,
      "name"        : name,
      "phoneNumber" : phoneNumber,
      "address"     : address,
    };
  }
}

Now we're ready to receive data from Firestore and convert it into our objects.

Lets see the code.

// Get the document with the ID of our personObject 
DocumentSnashot doc = await Firestore
.instance
.collection("collectionOfPersons")
.document(personID).get();
//Extract the data and create our object
Person personObject = Person.fromMap(doc.data); 
// doc.data => A Map<string,dynamic> data type returned by Firestore

These methods seem trivial, but when i was a beginner i never really understood their importance and their contribution to clean code principles. I use to manually do all of this in a function, which is definitely not a good practice as a developer.

Data models are an integral part of an Application and they should be flawless to ensure you focus on the main parts of the application instead of facing small issues like this issue i solved on StackOverflow a few minutes ago, which inspired me to create this article.

I am a Software Developer who is obsessed with producing clean and maintainable code following well-known Software Architectures. I write about problems i have faced myself and how i improved overtime. If you would like to see more such articles and learn about best practices, make sure to follow me.
Till next time, folks ! astalavista !

Top comments (0)