What is Cloud Firestore
Firestore is a NoSQL database
. It means data are not stored in tables but there are different ways to store them like the plain key-value store, a big nested tree (like the Realtime database) or a collection of JSON objects.
NoSQL databases are schema-less
. There's not a strict structure for data to respect.
Advantages of moving to the NoSQL model are:
-
scaling vertically
, when my app becomes popular and I need to scale up to a larger and larger data set, I generally need to put it on bigger and beefier machines -
scaling horizontally
, when I need to distribute data across several servers
What's inside the box
Cloud Firestore is made up of documents
and collections
.
Documents
are similar to JSON objects or dictionaries. They consist of key-value pairs, which are referred to as fields
. Values of these fields can be any number of things:
bird_type: "swallow"
airspeed: 42.733
coconut_capacity: 0.62
isNative: false
icon: <binary data>
vector: {
x: 36.4255,
y: 25.1442,
z: 18.8816
} // this is a map
distances_traveled: [
42, 39, 12, 42
]
Collections
are basically collections of documents. I can think of them like a hash or a dictionary where the values are always going to be some kind of document.
There are some rules to keep in mind using Firestore:
- a collection can only contain documents, nothing else
- a collection can only be 1 MG in size. Any larger than that I'll need to break it up
- a document cannot contain another document. Documents can point to subcollections, but not other documents directly
- the very root of a Cloud Firestore tree can only contain collections
Setting up the project
The application I'm going to build, uses Cloud Firestore via the Firebase SDK
. It will basically display a list of movies, fetching data from Firestore.
Creating the project on the Firebase console
To create a new project on Firebase, navigate to https://console.firebase.google.com/ and click on Add project
Once entered a good enough name for the project, I click Continue
. Finally, I disable the Google Analytics option and I click Create Project
.
After some seconds, the project is ready to be used.
Creating the application and adding the firebase configuration
npx create-react-app cinema-schedule
cd cinema-schedule
npm install firebase
Navigating to the project settings, I can see some options
I click the </>
icon to obtain the web configuration and to register the app.
At this point, to access Firestore
, I copy-paste the configuration object into App.js
...
import firebase from 'firebase';
const firebaseConfig = {
apiKey: "AIzaSyBkprReJ8s6qKBh1GaCoSgJLVuEYA1yucc",
authDomain: "cinema-schedule-43a09.firebaseapp.com",
databaseURL: "https://cinema-schedule-43a09.firebaseio.com",
projectId: "cinema-schedule-43a09",
storageBucket: "cinema-schedule-43a09.appspot.com",
messagingSenderId: "794350377365",
appId: "1:794350377365:web:9e47ac1a990cd22ade7e9c"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const database = firebase.firestore();
...
The variable database
is my point of access for Firestore
.
Fetching data
Before fetching some data from the database, I need to populate it! I navigate to the Database section
of Firebase and I select `Cloud Firestore.
To make the database readable and writable, I start it in test mode
. It's not recommended doing this in production databases.
Click Next
, select my project region and the Cloud Firestore is ready!
Now I am ready to perform my first query to get cinemas
from the database. In the App.js
file
Populate the database
As I said, I need to populate the database first. I can do it manually, via UI.
I create the first collection I need, cinemas
.
Then I create the first cinema, adding some details. I leave the Document ID
blank so Firebase will automatically create an auto ID
.
And I'm done! Now I have a collection cinemas
that contains a document represeting a cinema.
To add a new cinema, I click on Add document
.
Now I can fetch data from the code
javascript
...
database.collection('cinemas').get()
.then(response => {
console.log(response.docs);
})
.catch(error => {
console.log(error);
});
...
The .get()
is an asyncronous function so I handle the request with the classic then - catch
block. In the browser console I see
Note how Firebase automatically generated the document ID. To get data in an accessible way, I do
javascript
database.collection('cinemas').get()
.then(response => {
response.docs.forEach(document => {
console.log(document.data());
});
})
.catch(error => {
console.log(error);
});
In the browser console I obtain
{city: "Galway", name: "The Space Cinema", total_seats: 500}
{city: "Dublin", name: "Irish Multiplex", total_seats: 1200}
Displaying data in the UI
To display cinemas, I store them into the state
, using React hooks
. It's straight forward, at that point, to display a list of elements.
import React, { useState, useEffect } from 'react'; | |
import firebase from 'firebase'; | |
const firebaseConfig = { | |
apiKey: "AIzaSyDQXMsyejsUgPj-1ZPIyL9YMKdhZ280Mwo", | |
authDomain: "cinema-schedule-7bfa4.firebaseapp.com", | |
databaseURL: "https://cinema-schedule-7bfa4.firebaseio.com", | |
projectId: "cinema-schedule-7bfa4", | |
storageBucket: "cinema-schedule-7bfa4.appspot.com", | |
messagingSenderId: "215540682675", | |
appId: "1:215540682675:web:6e6e792cb9f041ae8e05c6" | |
}; | |
// Initialize Firebase | |
firebase.initializeApp(firebaseConfig); | |
const database = firebase.firestore(); | |
const App = () => { | |
const [cinemas, setCinemas] = useState([]); | |
const [error, setError] = useState(); | |
useEffect(() => { | |
database.collection('cinemas').get() | |
.then(response => { | |
const fetchedCinemas = []; | |
response.docs.forEach(document => { | |
const fetchedCinema = { | |
id: document.id, | |
...document.data() | |
}; | |
fetchedCinemas.push(fetchedCinema); | |
}); | |
setCinemas(fetchedCinemas); | |
}) | |
.catch(error => { | |
setError(error); | |
}); | |
}, []); | |
return ( | |
<div> | |
{error ? ( | |
<p>Ops, there is an error :(</p> | |
) : null} | |
<ul> | |
{cinemas.map(cinema => ( | |
<li key={cinema.id}>{cinema.name}</li> | |
))} | |
</ul> | |
</div> | |
); | |
} | |
export default App; |
The list of cinemas is correctly displayed!
Top comments (0)