How to Convert Realtime Database Events to Promises in Firebase

The Realtime Database api in Firebase is based on callbacks. This could be fine for you if you are maintaining a codebase which is a few years old.

But, if you prefer a Promise, or better yet async await approach, you will be down for a little dissapointment.

A typical function that you write for retreviing data from a particular path in the Realtime database will look like as follows:

1
2
3
4
5
6
7
8
9
10
11
const admin = require('firebase-database');
const realtimeDb = admin.database();
const ref = realtimeDb.ref(`/path/to/the/data`);

/** Called on `value` event */
const onDataCallback = data => {
// Do whatever you want with the data
console.log('data:', data);
};

ref.on('value', onDataCallback);

We are dealing with callbacks here, so we cannot use then(), or await for our async operations.

Let us start with an example.

Let’s suppose, you want to fetch data from the path:

1
/Users/usernames/hopelesspuppy

For that, you would first need to create a reference to this path.

1
const ref = admin.database().ref('/Users/usernames/hopelesspuppy');

Suppose you want to fetch some data from a certain path from the Realtime Database. To fetch the data using the ref, you would write your code as follows:

1
2
3
4
5
6
7
8
const getData = ref => {
return Promise((resolve, reject) => {
const onData = data => resolve(data));
const onError = error => reject(error));

ref.on('value', onData, onError);
});
}

If you have read the docs, you’d know how this code works.

But, for the uninitiated, let me reiterate.

1
ref.on('value', onData, onError)

The ref denotes the reference to the item in the database which you want to perform an action like read or write.

When you set a value event on the item reference in the Realtime database, one of the callbacks you provide will be called.

In this instance, I have named my callbacks onData and onError.

As the name suggests, if the retrieval is successful, the onData function will execute with the snapShot of the object. You an access its value using the .val() method on that snapshot.

In case of an error, your the onError function will execute where I’m only printing the error as a string.

1
2
3
4
5
6
7
const onData = snapShot => {
console.log(snapShot.val());
};

const onError = error => {
console.log('Error retrieving the data:', error.toString());
};

So, how do we convert this callback based code into a Promise.

The answer is simple. Use the Promise constructor.

Or to be more precise, you just wrap your callback code into a Promise constructor. This constructor resolves or rejects based on onData or onError callback excution.

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const getData = ref => {
return new Promise((resolve, reject) => {
const onError = error = reject(error);
const onData = snap => resolve(snap.val());

ref.on('value', onData, onError);
});
};

getData(ref)
.then(value => {
// resolve() was called
})
.catch(error => {
// reject() was called
// Something went wrong while fetching the data.
// Handle that error here.
});

That is all.