May all of you get Good News about Cloud Firestore by Firebase.
As I want to convert my Firebase Database to Cloud Firestore is there any simple way to convert It?
I want to move on Cloud Firestore.
Cloud Firestore is Firebase's newest database for mobile app development. It builds on the successes of the Realtime Database with a new, more intuitive data model. Cloud Firestore also features richer, faster queries and scales further than the Realtime Database. Realtime Database is Firebase's original database.
If you have a very time-sensitive app, like online auctions where you can't have unpredictable delays (no one likes to lose because of something that we don't control), you shouldn't really use Firestore. You will have a hard time hiding the hiccups and you will only anger your users.
Firestore is perfectly usable on the backend without a client app. But if you are shipping an app, I'd strongly recommend integrating Firebase Authentication first, and you should think carefully about structuring your data and rules from there.
I write myself guides as I learn new things. Here's my guide describing how I migrated my Realtime Database to Cloud Firestore. You can skip the first section. I write in Markdown, some of the code markup doesn't translate to StackOverflow's markup. If you have trouble reading it I'll email you the original Markdown version. Now I'm working on updating my controllers to Cloud Firestore queries.
For more than two years my go-to stack has been Angular and Firebase. Data binding caught my eye--if a user changes data in the view, the data instantly changes in the controller and in the cloud database. Or any other order of events. My first Firebase project was a tic-tac-toe game where two players could play remotely, with my click appearing instantly on your screen, and vice versa, with the cloud database updating in between. (Firebase calls this "synced states across clients in realtime.")
I also like Firebase's Auth library. Setting up OAuth2 user login wth Facebook, Google, Twitter, GitHub, or a phone number, or old-school email and password, is easy.
I like not having to deal with setting up and maintaining a server.
And I like using a NoSQL database. I use arrays of objects in JavaScript, so why not use the same data structure in the database?
I don't need this, but mobile app developers can use Firebase Realtime Database's off-line capabilities. When the user is out of service range, the database can continue to update, so that when the user comes back online he or she can access current data.
Plus Firebase has Storage for large binary files such as pictures, audio, and video.
What's not to like about Firebase Realtime Database? The queries. My dog has so many neighborhood girlfriends that I need a database to keep track of them all. I want to call China's owners to invite her over for a play date. To get their phone number isn't easy. I can't tell Firebase to look in the array dogs
, find the object with name
equal to China
, and return the field phone_number
. I have to tell Firebase to download the entire array, then run a forEach
loop to iterate over each object, looking for name === China
. This is called a "deep query" because it returns every object in the array, and every sub-array, and all the nested sub-levels. My dog has so many girlfriends that it can take seconds to download them all!
Firebase Realtime Database has sorting, so I can download the array of neighborhood dogs ordered by name, age, etc. I can filter, e.g., only dogs more than five years old, but Firebase Realtime Database can't sort and filter.
The key to finding a specific object in the Firebase Realtime Database is to know its key. Keys are lightweight objects that look like -KloeQHDC-mugPjJMAG4
. If you keep track of an object's key, you can easily retrieve the object from the database. E.g., when a new user logs in with Facebook and creates a record in the Auth database, and you then create a user account in the Realtime Database, you can make the user's auth key a key-value pair in the user's account so that you can easily find the auth data (displayName
, photoURL
, etc.) associated with this user.
With one database for Auth, another for binary file Storage, and a third database for everything else, you have a lot of keys to keep track of.
For big data projects, Firebase Realtime Database has additional limitations. The data can only nest 32 layers deep. Scaling up requires sharding. If your client is doing big data, or delusionally thinks that his 5000 records is big data, you'll have some arguing to do to persuade your client not to use SQL on a server.
Why? The queries! With Cloud Firestore I can now query my dogs
array, requesting the record with the name
equal to China
. Firebase returns only the object I want.
Cloud Firestore can sort and filter data.
Cloud Firestore can handle subcollections within documents. You can request an document that contains subcollections of documents, and just get the document, without it's subcollections. I.e., shallow queries. You can even delete a document that contains subcollections of documents, and keep the subcollections.
Cloud Firestore also scales better than Firebase Realtime Database. The security is better, and there are other new features and improvements.
First, you need to add Cloud Firestore to your project. In your index.html
file after you link to the Firebase CDN, link to the Cloud Firestore CDN:
<script src="https://www.gstatic.com/firebasejs/4.5.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.5.0/firebase-firestore.js"></script>
Or download the Node module and link to it:
npm install [email protected] --save
If you're using the Firebase SDK on a Node server you'll also need to add a dependency:
const firebase = require("firebase");
// Required for side-effects
require("firebase/firestore");
Also in index.html
you'll need to initialize the app:
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});
If you're also using Firebase Realtime Database, Storage, and Cloud Messaging you'll have more stuff:
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
databaseURL: "https://###.firebaseio.com",
messagingSenderId: "###",
projectId: '### CLOUD FIRESTORE PROJECT ID ###',
storageBucket: "###.appspot.com"
});
And, finally, make a reference to Cloud Firestore in your controller:
var db = firebase.firestore();
Next, you'll want to migrate your data from Firebase Realtime Database to Cloud Firestore. This is easy.
return firebase.database().ref('dogs').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
snapshot.forEach(function(childSnapshot) { // iterate through the user's data
let childData = childSnapshot.val(); // this is the user's data
db.collection('dogs').doc(childData.dog).set(childData); // each dog is written to Cloud Firestore
})
});
Don't do this:
return firebase.database().ref('dogs').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
db.collection('dogs').set(snapshot); // copy the array to Cloud Firestore
});
The latter will copy the Firebase Realtime Database keys. It also won't work because you can't upload collections to Cloud Firestore, you can only upload documents.
In the former example, the forEach
loop iterates through each record and uploads it as a document to Cloud Firestore. The collection is created automatically and named dogs
. This also removes the Firebase Realtime Database keys and replaces them with Cloud Firestore keys.
The return
stops any code executing after this command. If you want to migrate many arrays, then use return
only on the last command:
firebase.database().ref('dogs').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
snapshot.forEach(function(childSnapshot) { // iterate through the user's data
let childData = childSnapshot.val(); // this is the user's data
db.collection('dogs').doc(childData.dog).set(childData); // each dog is written to Cloud Firestore
})
});
firebase.database().ref('cats').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
snapshot.forEach(function(childSnapshot) { // iterate through the user's data
let childData = childSnapshot.val(); // this is the user's data
db.collection('cats').doc(childData.cat).set(childData); // each cat is written to Cloud Firestore
})
});
return firebase.database().ref('cetaceans').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
snapshot.forEach(function(childSnapshot) { // iterate through the user's data
let childData = childSnapshot.val(); // this is the user's data
db.collection('cetaceans').doc(childData.cetacean).set(childData); // each whale and dolphin is written to Cloud Firestore
})
});
Firebase Realtime Database allows you to have arrays in arrays, objects in objects, arrays in objects, or objects in arrays. Cloud Firebase only allows documents (objects) in collections (arrays), and collections in documents. In other words, Cloud Firebase data is always structured collection - document - collection - document, etc.
Perhaps you want to copy a nested array to a subcollection:
return firebase.database().ref('dogs').child('girlfriends').once('value') // get a snapshot of the user's data
.then(function(snapshot) { // then execute a promise on the snapshot
snapshot.forEach(function(childSnapshot) { // iterate through the user's data
let childData = childSnapshot.val(); // this is the user's data
db.collection('dogs').doc(childData.word).set(childData); // write the data to Cloud Firestore
db.collection('dogs').doc('dogs').collection('girlfriends').doc(childData.dog).set(childData);
})
});
Here we are getting the array girlfriends
from the array dogs
, iterating through the array with a forEach
loop, and writing each record to a collection girlfriends
in a document dogs
in a collection dogs
. I named both the top collection and the top document dogs
. You could use different names.
Now we'll get started updating our code.
We've already updated one line of code. We updated our Firebase Realtime Database reference:
let ref = firebase.database().ref();
to Cloud Firestore:
let db = firebase.firestore();
You can leave the Firebase Realtime Database reference for the moment, and then comment it out or remove it when we're finished.
I have one other Firebase Realtime Database reference, to my users
array:
let users = firebase.database().ref('users');
We'll update that to:
let usersFS = firebase.firestore().collection('users');
We'll use different names so that we can run both databases together, until we've finished our migration.
Now we can start updating our queries. In my controller, my first firebase.database().ref
query is:
firebase.database().ref('userLoginEvent').update({'user': user.uid})
For Cloud Firestore we instead use:
db.collection('userLoginEvent').doc('HUSEj7dPh8xsOw32feQY').update({'user': user.uid});
The code is almost identical except that Cloud Firestore requires specifying a document in a collection. Here I reference the document's key because this command always writes to the same location in the database.
Next, I have:
firebase.database().ref('users').child($scope.userAccountKey).update(englishWords);
We'll update that to:
db.collection('users').doc($scope.userAccountKey).update(englishWords); // this isn't working
That name is too long! Looking up domain names, I see that fire.me
is still available. I wonder why no one in marketing suggested that short, memorable domain name?
Since the data models are so different, there isn't an automatic way to achieve this. You'll need to write your own method based on the needs of your app.
The documentation provides an overview of the differences.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With