Firebase: Cloud Firestore Data Types, Costs, & Query Examples

By: Jeff Lewis

Jeff Lewis
5 min readApr 29, 2019

Notes:

1. Data Types

Think of a document as a user object and a collection as an array of users.

Document

  • A record that contains fields, which map to values.
  • Documents are limited to 1 MB in size.

Collection

  • A container for documents.

2. Cloud Firestore Billing & Costs

Cloud Firestore focuses more about the number of operations performed, rather than how much is downloaded. Please check the Cloud Firestore Pricing and Daily Free Quota. Here i1s how Cloud Firestore charges:

Billing:

  • The number of reads, writes, and deletes that you perform.
  • The amount of storage that your database uses, including overhead for metadata and indexes.
  • The amount of network bandwidth that you use. The network bandwidth cost of a Cloud Firestore request depends on the request’s response size, the location of your Cloud Firestore database, and the destination of the response.

Pricing:

Documents Reads (per 100,000): $0.06

Documents Writes (per 100,000): $0.18

Documents Deletes (per 100,000): $0.02

Stored Data: $0.18 per GB

Document Read:

A Document Read occurs when a client gets data from a document. For example, you are building a restaurant review app and you want to query for sushi restaurants by zip code. If your Cloud Firestore has 10,000 restaurants, but only of 800 sushi restaurants, and only 50 of them are sushi restaurants in your zip code, you will only be charged for the 50 documents that were sent to the client. Only the documents retrieved are counted towards what you are charged.

Note: If you’re trying to limit the data returned from Cloud Firestore by a certain amount, we will get into Limit and Pagination in a bit.

Document Write:

A Document Write occurs when a data is written to the database. For instance, a document read can be for creating a user profile, updating details on a user profile, saving user favorites, and etc.

4. Querying (Find Data)

Cloud Firestore Limitations:

Queries are shallow, which means the sub collections won’t be returned. You’ll either have to fetch multiple queries or break up the sub collections.

You also cannot query part of a document (See #3 Cloud Firestore Billing & Costs).

Speed:

The time it takes run a Cloud Firestore query is proportional to the number of documents you receive, not the number of documents you are searching through. This is because every document in Cloud Firestore is Indexed. This means every entry in the index records the value of the field (You data) + where the corresponding document is located in Cloud Firestore.

Cloud Firestore is essentially a sorted list, so Cloud Firestore uses an algorithm similar to Binary Search. If you’re not familiar with Binary Search, it is a Search Algorithm that only works on a sorted list and cuts the search time in half at each step.

3. Querying Examples

If you haven’t loaded JSON data to Cloud Firestore, please first check out my guide to Import JSON to Cloud Firestore.

Note: The firebase dependency + firebase config file (ADD THIS FILE TO YOUR GITIGNORE) must be added to perform a query.

Example: Query (Single Document):

config.js

// Firebase Config
const firebaseConfig = {
apiKey: 'API_KEY_HERE',
authDomain: 'AUTH_DOMAIN_HERE',
databaseURL: 'DATABASE_URL_HERE',
projectId: 'PROJECT_ID_HERE',
storageBucket: 'STORAGE_BUCKET_HERE',
messagingSenderId: 'MESSAGE_SENDER_ID_HERE',
}
// Exports
module.exports = firebaseConfig;

query.js

// Imports: Dependencies
const firebase = require('firebase');
const firebaseConfig = require('../config/config');
// Firebase: Initialize
firebase.initializeApp({
apiKey: `${firebaseConfig.apiKey}`,
authDomain: `${firebaseConfig.authDomain}`,
databaseURL: `${firebaseConfig.databaseURL}`,
projectId: `${firebaseConfig.projectId}`,
storageBucket: `${firebaseConfig.storageBucket}`,
messagingSenderId: `${firebaseConfig.messagingSenderId}`,
});
// Firebase: Database + Settings
const db = firebase.firestore();
// Cloud Firestore Collection: Users
db.collection('users')
.where('id', '==', '007')
.get()
.then((document) => {
// Display Retrieved Data To Console
console.log(document.data());
})
.catch((error) => {
console.log(`Error getting documents: ${error}`);
});

Example: Query (Multiple Documents):

config.js

// Firebase Config
const firebaseConfig = {
apiKey: 'API_KEY_HERE',
authDomain: 'AUTH_DOMAIN_HERE',
databaseURL: 'DATABASE_URL_HERE',
projectId: 'PROJECT_ID_HERE',
storageBucket: 'STORAGE_BUCKET_HERE',
messagingSenderId: 'MESSAGE_SENDER_ID_HERE',
}
// Exports
module.exports = firebaseConfig;

query.js

// Imports: Dependencies
const firebase = require('firebase');
const firebaseConfig = require('../config/config');
// Firebase: Initialize
firebase.initializeApp({
apiKey: firebaseConfig.apiKey,
authDomain: firebaseConfig.authDomain,
databaseURL: firebaseConfig.databaseURL,
projectId: firebaseConfig.projectId,
storageBucket: firebaseConfig.storageBucket,
messagingSenderId: firebaseConfig.messagingSenderId,
});
// Firebase: Database + Settings
const db = firebase.firestore();
// Cloud Firestore Collection: Users
db.collection('users')
.where('age', '>=', '21')
.where('name', '==', 'Jeff')
.where('tags', 'array-contains', 'Programmer')
// A Limit Can Be Set For Records Returned. You Are Charged Per Data Returned
.limit(10)
.get()
.then((querySnapshot) => {
// Iterate Through Query Data
querySnapshot.docs.forEach((document) => {
// Display Retrieved Data To Console
console.log(document.data());
// Entire Query Snapshot. Uncomment The Next Line To View
console.log(querySnapshot);
});
})
.catch((error) => {
console.log(`Error getting documents: ${error}`);
});

4. Cloud Firestore Security Rules

To modify Cloud Firestore Security Rules, navigate to the Database tab on the left sidebar. Click on Rules.

Additionally, all match statements should point to documents, not collections.

Read Rules:

  • Get (Read single document)
  • List (Read queries & collection)

Write Rules:

  • Create (Write to nonexistent documents)
  • Update (Write to existing documents)
  • Delete

Example: Service & Database Declaration (Default No Read/No Write)

Note: The match /databases/{database}/documents declaration specifies that rules should match any Cloud Firestore database in the project.

// Cloud Firestore Service Declaration
service cloud.firestore {
// Database Declaration
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}

Example: Service & Database Declaration (Read Only)

// Cloud Firestore Service Declaration
service cloud.firestore {
// Database Declaration
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if false;
}
}
}

4. Enable Billing & Set Cloud Firestore Budget

Note: Apps that haven’t enabled billing on your project or using the free tier, this section won’t apply to you. Once your project is ready for production, you can enable billing and set a Budget.

If you’re like me, I’d rather not have an unlimited spending limit at my expense in case there is an issue somewhere. Billing and spending limits be enable through the Google Cloud Platform Console.

Enable Billing:

  1. Go to the Google Cloud Platform Console.
  2. From the projects list, select the project to re-enable billing for.
  3. Open the console left side menu and select Billing .
  4. Click Link a billing account.
  5. Select a billing account, then click Set account.

Set Cloud Firestore Budget:

  1. Go to the App Engine Application Settings.
  2. Click Edit and set a Daily spending limit.
  3. Click Save (The new limit takes effect immediately).

5. Google Stackdriver

Google Stackdriver is a freemium, credit card required, cloud computing systems management service offered by Google. It provides performance and diagnostics data (in the form of monitoring, logging, tracing, error reporting, and alerting) to public cloud users.

Note: Stackdriver is a hybrid cloud solution, providing support for both Google Cloud and AWS cloud environments.

--

--

Jeff Lewis

Full stack React/React Native developer, environmentalist, and beach bum.