Skip to Content
FirebaseCalling Cloud Firestore APIs

Calling Cloud Firestore APIs

Cloud Firestore  is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud. Ensemble platform provides a deep integration with the Firestore DB and allows you to call operations on your data in Firestore effortlessly.

Unlike traditional relational databases, Firestore offers a document-based structure well-suited for storing and managing various data types within oour app. Firestore is a great choice for Ensemble applications because it provides simplified data modeling, Offline Persistence, Real-time Updates, and API Convenience to interact with data.⁤

Now, let’s dive into performing basic operations on our Firestore database:

Operations on Firestore won’t work unless we have configured our Ensemble application with Firebase. Learn how to configure it here.

  • To get hands-on experience with firestore operations, check the live example on Ensemble Studio 

Firestore Data types

Timestamp

Following methods are available for Firestore’s Timestamp type.

Timestamp.now()

Static method. Returns a Timestamp representing the current time.

Example

var currentTimestamp = Timestamp.now(); console.log(currentTimestamp);

Timestamp.fromDate(date)

Static method. Creates a Timestamp from a JavaScript Date  object. Example

var specificDate = new Date('2024-08-05T12:34:56Z'); var specificTimestamp = Timestamp.fromDate(specificDate); console.log(specificTimestamp);

Timestamp.fromMillis(milliseconds)

Static method. Creates a Timestamp from a given number of milliseconds since the Unix epoch (January 1, 1970).

Example

var milliseconds = 1691237696123; // Milliseconds since the Unix epoch var timestampFromMillis = Timestamp.fromMillis(milliseconds); console.log(timestampFromMillis);

new Timestamp(seconds, nanoseconds)

Constructor. Creates a Timestamp object from a given number of seconds since the Unix epoch and additional nanoseconds.

Example

var seconds = 1691237696; var nanoseconds = 123456789; var customTimestamp = new Timestamp(seconds, nanoseconds); console.log(customTimestamp);

toDate()

Converts a Timestamp to the number of milliseconds since the Unix epoch. Example

var milliseconds = customTimestamp.toMillis(); console.log(milliseconds);

valueOf()

Returns the number of milliseconds since the Unix epoch, similar to toMillis(). It’s used when Timestamp is compared to other values in arithmetic operations.

Example

var value = customTimestamp.valueOf(); console.log(value);

Following properties are also available on each Timestamp object

seconds

The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.

Example

var timestamp = new Timestamp(10,0); console.log(timestamp.seconds); //prints 10

nanoseconds

The number of nanoseconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.

Example

var timestamp = new Timestamp(10,0); console.log(timestamp.nanoseconds); //prints 0

FieldValue

Other than isEqual, Ensemble platform supports all the methods for FieldValue .

All the methods are static and are called exactly the same way as you could call in js, see this  for example.

See the following paragraphs for examples of how to use FieldValue.serverTimestamp()

1. Creating a Firestore Collection

To store data in Firestore, we need to create a collection. A collection in Firestore is a container for documents, which are individual pieces of data. Each document contains a set of key-value pairs. Follow the given steps to create a collection:

  • Go to the Firebase Console.
  • Select our project.
  • Navigate to Firestore Database in the side menu.
  • Click on Start collection.
  • Enter a collection ID (e.g., sports).
  • We can add our first document by entering a document ID or let Firestore auto-generate one for us.
  • Add fields and values to our document.
  • Click Save.

By default, firestore rules do not allow anyone to access our database. To get started with it, update the rules by changing it to allow read, write; which allow everyone to access our database and then update the rules according to our requirements.

2. Types of Firestore Operations

Firestore offers various operations to interact with our data. Here’s a breakdown of some core operations along with demo API calls for our Ensemble app

Get:

This operation retrieves data from our Firestore collections. We can either retrieve entire collections or use queries to filter and sort our data.

  1. Example (Get all users):
getUsers: type: firestore path: users listenForChanges: true

Explanation:

  • type: firestore: Specifies that the operation is for Firestore and it is not a RestAPI.
  • path: The path to the collection or document from where we wanna retrieve the data.
  • listenForChanges: The operation will listen for real-time updates if set to true and triggers the UI to update.

Default vale for operation is set to add if not mentioned.

Note: When listenForChanges is set to true, the first response from the API will be {"message": "Subscribed to API", "documents": []}. Be aware of this if your response handling involves checking whether documents is empty.

  1. Example (Get user using multiple filters):
getSpecificUsers: inputs: - userId type: firestore path: example/users query: where: - field: _documentId operator: == value: ${userId} orderBy: - age limit: 10

Explanation:

  • inputs: We can also use dynamic variables in the path or a query.
  • path: Path can be any based on our collections and documents we are trying to access.
  • query: Filters the data based on the conditions such as where . orderBy, Limit .

Add:

The add operation creates a new document in a collection with a specified or auto-generated ID.

  1. Example:
createProject: inputs: - userId - proName - proDes - proFiles type: firestore path: users/${userId}/Projects operation: add data: proName: ${proName} description: ${proDes} createdAt: ${FieldValue.serverTimestamp()}

Explanation:

  • operation: add: Indicates that a new document will be created.
  • data: The fields and values for the new document. Note how FieldValue is being used to tell Firestore to set the server timestamp

Set:

The set operation can create a new document if it does not exist but if the document already exists, set will overwrite the entire document with the data provided, unless we use the merge option.

  1. Example:
setProject: inputs: - userId - projectID - proName - proDes - proFiles type: firestore path: users/${userId}/Projects/${projectID} operation: set data: proName: ${proName} description: ${proDes} setAt: ${FieldValue.serverTimestamp()}

Update:

The update operation only updates the fields specified in the provided data. If the document does not exist, update will fail with an error.

  1. Example:
inputs: - userId - projectID type: firestore path: users/${userId}/Projects/${projectID} operation: update data: # Below files will be stored as Array of objects. files: [{ name: "index.js" , lines: 78 },{ name: "LMS.js" , lines: 245 }] lastUpdated: ${FieldValue.serverTimestamp()}

Delete:

The delete operation removes a document from a collection.

  1. Example:
deleteProject: inputs: - userId - projectID type: firestore path: users/${userId}/Projects/${projectID} operation: delete

Collection Group:

The isCollectionGroup feature is used to retrieve specific collections from any collection. For example, if we have 100 documents in the users collection and each document has a sub-collection named projects, the isCollectionGroup feature helps in getting all projects directly rather than iterating through each document.

  1. Example:
getAllProjects: type: firestore path: Projects isCollectionGroup: true

3. Response of Firestore Operations

When performing Firestore operations, we may need to manipulate the responses to fit our application’s needs. Below are some common ways demonstrating how to use YAML for API calls, handle states, and display data in our app.

1. Firstly, we will make an API call as follow:

invokeAPI: name: getProjects inputs: userId: ${userID}

We can also use onResponse & onError on firebase API calls and can perform operations on response.

2. Using response in Column:

To display data based on the API call’s state (loading, success, error), you can use the following structure:

Column: children: - Column: styles: visible: '${getProjects.isLoading ? true : false}' children: - Progress: display: circular - Column: styles: visible: '${getProjects.isSuccess ? true : false}' item-template: data: ${getProjects.body.documents} name: project template: projectDisplay: # that is an custom widget. inputs: name: ${project.proName} des: ${project.description} - Column: styles: visible: '${getProjects.isError ? true : false}' children: - Text: text: "An error has occurred"
  • Explanation:
    • The first child Column is visible only when the API call is loading (visible: '${getProjects.isLoading ? true : false}'). It shows a circular progress indicator.
    • The second child Column is visible only when the API call is successful (visible: '${getProjects.isSuccess ? true : false}'). It iterates over the documents in the response body using item-template.
    • The third child Column is visible only when there is an error (visible: '${getProjects.isError ? true : false}'). It shows an error message.

3. Using response in Dropdown:

To display data in a dropdown, we can use the following YAML structure:

Dropdown: id: selectProject label: Select Project itemTemplate: data: ${getProjects.body.documents} name: project value: ${project._documentId} template: Text: text: ${"Name:" + " " + project.proName}

By using these operations, we can efficiently manage our data in Firestore with an Ensemble project. Firestore’s real-time capabilities and simple API calls make it a powerful tool for any application.

Last updated on