Opposite to what you might expect, we haven’t used a lot of prehistorical 🦕 technologies for the development of T-Rex Time Registration. Actually, the service we use as back-end has been launched just over a month ago: Google Cloud Firestore. Cloud Firestore is part of the terrific Google Firebase suite. 🔥

Being familiar with Google Firebase, we were immediately intrigued by this new database solution. We’ve built a few mobile apps on the Firebase Realtime Database (e.g. Windpark Westermeerwind and Gemini Wind Park), and although we love it’s possibilities and ease of use, we also encountered it’s limitations. Especially executing more complex queries is very difficult with the Realtime Database.

This article will touch on some of our experiences developing with Google Cloud Firestore.

What is Cloud Firestore?

Just like the Firebase Realtime Database, Cloud Firestore is a fully managed NoSQL database, with SDK’s for web (JavaScript), mobile (Java for Android and Swift and Objective-C for iOS) and back-end (Node.js, Python and Java). Whereas the Realtime Database is a live-updating JSON tree, the Firestore uses documents grouped in collections.

One of the benefits of this is the difference between a document’s properties and it’s sub collections. Fetching a node in the Realtime Database gives you all of its sub nodes, while Firestore’s structure allows you to fetch just a node’s own properties without all of it’s sub nodes.

Security Rules

Similarly to the Firebase Realtime Database, all database permissions and data validation for the Firestore database is defined in Cloud Firestore Rules. However, these rules have a different syntax then the Realtime Database Rules. Let’s compare the simple permission of a user to edit his own user object:

Firebase Realtime Database

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow write: if request.auth.uid == userId;
    }
  }
}

Note: in both cases users have to authenticate through Firebase Authentication.

One of the nice additions in Cloud Firestore Rules is the possibility to define functions. Say you want to make a particular object writable for admins only, you could do this:

service cloud.firestore {
  match /databases/{database}/documents {
    match /objects/objectWritableByAdminOnly {
      allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin;
    }
  }
}

But, if you’d want to do this same check at other places it would get real messy real quick. Luckily, with Firestore Rules you can do the following:

service cloud.firestore {
  match /databases/{database}/documents {
    function currentUserData() {
      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
    }
    match /objects/objectWritableByAdminOnly {
      allow write: if currentUserData().admin;
    }
  }
}

More on Firestore and other technologies, soon

While developing with Firestore we learned a lot and we’d love to share these experiences. More of these articles will follow soon!