Skip to content

Reading Data

Getting Started

We can retrieve data that has been stored in Flybase by attaching an asynchronous listener to a Flybase reference. In this document, we will cover the basics of retrieving data, how Flybase data is ordered, and how to perform queries on Flybase data.

Let’s revisit our example from the previous article to understand how we read data from Flybase.

To simply read our post data, we can do the following:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Attach an asynchronous callback to read the data at our posts reference
ref.on("value", function(snapshot) {
console.log( snapshot.value() );
});

If we run this code, we’ll see an object containing all of our posts logged to the console.

The callback function will receive a snapshot, which is a snapshot of the data. A snapshot is a listing of the data in a Flybase app at a single point in time, this could be one document or multiple documents, depending on the query being called, and the number of records that are returned.

Calling .value() on a snapshot returns the JavaScript object representation of the data. If no data exists at the location, the snapshots value will be null.

You may have noticed that we used the value event type in our example above, which reads the entire contents of a Flybase collection. value is one of the five different reserved event types that we can use to read data from Flybase. We’ll discuss the other four event types below.

When reading data, we have access to a few methods besides .value(), we can use .count() to get a count of the number of records returned and we can use .forEach() to iterate through each record:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Attach an asynchronous callback to read the data at our posts reference
ref.on("value", function(snapshot) {
console.log( "we found " + snapshot.count() + " posts");
if( snapshot.count() ){
snapshot.forEach( function( post ){
console.log( post.value() );
});
}
});

The .count() method will return null if no documents were found, this can be handy for making sure data actually exists so we don’t trigger any errors.Reserved Events

Reserved Events are events that are triggered when certain events happen, such as retrieving documents, adding a new document, changing a document, deleting documents or even when a device connects or disconnects.

These events will always happen, so it’s up to you to decide how you want to listen to them and handle them.Value

Whenever you query data, the value event is used to read the contents of a given collection.

When the value event is triggered, the event callback is passed a snapshot containing all document data.

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Attach an asynchronous callback to read the data at our posts reference
ref.on("value", function(snapshot) {
console.log( "we found " + snapshot.count() + " posts");
snapshot.forEach( function( post ){
console.log( post.value() );
});
});

Document Added

The added event is typically used when retrieving a list of items in Flybase. Unlike value which returns the entire contents of the location, added is triggered once every time a new document is added to the specified collection. The event callback is passed a snapshot containing the new document’s data.

If we wanted to retrieve only the data on each new post added to our blogging app, we could use added:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Retrieve new posts as they are added to Flybase
ref.on("added", function(snapshot) {
const post = snapshot.value();
console.log("Author: " + post.author);
console.log("Title: " + post.title);
});

In this example the snapshot contains an object with an individual blog post. Because we converted our post to an object using .value(), we have access to the post’s author and title properties by calling by calling .author and .title respectively.Document Updated

The changed event is triggered any time a document is modified. Normally, it is used along with added and removed to respond to changes to a list of items. The snapshot passed to the event callback contains the updated data for the document.

We can use changed to read updated data on blog posts when they are edited:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Get the data on a post that has changed
ref.on("changed", function(snapshot) {
const post = snapshot.value();
console.log("The updated post title is " + post.title);
});

Document Removed

The removed event is triggered when a document is removed. Normally, it is used along with added and changed. The snapshot passed to the event callback contains the data for the removed document.

In our blog example, we’ll use removed to log a notification about the deleted post to the console:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// Get the data on a post that has been removed
ref.on("removed", function(snapshot) {
const post = snapshot.value();
console.log("The blog post titled '" + post.title + "' has been deleted");
});

Device Connected / Disconnected

The online event is triggered whenever another device connects or disconnects from a Flybase app.

In our example, we’ll use online to log a notification about the number of connected devices to the console:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
messagesRef.on('online', function (data) {
const online = data.value();
console.log( "There are " + online + " devices connected");
});

Custom Events

You can also listen for custom events, these are events that don’t read or write to your Flybase app, but can be set up to trigger another action.

For example, you can use this to notify a user of an event:

const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.on("custom_event", function(message) {
console.log( message );
});
ref.trigger("custom_event", "Hi")

In the above example, we set up a listener for a custom event called custom_event and then triggered it using the .trigger() function, whenever the custom_event event is triggered, we will display the message in the console. This could be used to listen to any type of notification.

Handling How Data Is Returned

Flybase gives you a query engine that lets you selectively retrieve data based on various factors.

To construct a query in Flybase, you start by specifying how you want your data to be ordered using the orderBy ordering function. You can then combine these with other methods to conduct complex queries: limit()skip(), and where().Ordering Data

We can order data by a common key by passing that key to orderBy(), followed by 1 for Ascending or -1 for Descending sort order. For example, to sort all posts by author, we can do the following:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.orderBy({"author": 1}).on("value", function(snapshot) {
console.log( snapshot.value() );
});

You may notice that our orderBy() function takes an object. We’ve built our query engine heavily based on the MongoDB standard, so you can order by specifying the field, and then 1 for Ascending or -1 for Descending sort order. You can also add other fields as well:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.orderBy({"author": 1,"date": -1}).on("value", function(snapshot) {
console.log( snapshot.value() );
});

Now that we’ve specified how your data will be ordered, we can use the limit or skip methods described below to construct more complex queries. On top of that, we can actually perform queries using our query builder.Limiting Data

The limit() function is used to set a maximum number of documents to be synced for a given callback. If we set a limit of 100, we will initially only receive up to 100 documents.Skipping Data

Using skip() allows us to choose arbitrary starting and ending points for our queries. This is useful for pagination when combined with limit().Querying Data

The most powerful function you can use for querying data is the where() function, this lets you build queries similar to a database. For example, if we only wanted to return posts that were written by baileys, we can do the following query:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.where({"author": "baileys"}).on("value", function(snapshot) {
console.log( snapshot.value() );
});

This will return all posts that were written by baileys.

We can combine all our functions, for example, we can return posts written by baileys and sort by date:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.where({"author": "baileys"}).orderBy({"date": 1}).on("value", function(snapshot) {
console.log( snapshot.value() );
});

Just as with the orderBy() functionality, we’ve built our queries based on MongoDB, so there are a few commands you can use to perform queries, which can help build pretty advanced apps:

status is "A":

{ "status": "A" } or { "status": { "$eq": "A" } }

status is NOT "A":

{ "status": { "$not": "A" } }

age > 25:

{ "age": { "$gt": 25 } }

status is "A" AND age > 25:

{ "$and": [ {"status": "A" }, {"age": { "$gt": 25 } } ] }

name contains "bc":

{ "name": { "$regex":"bc" } }

name is either ‘bob’ or ‘jake’:

{ "name" { "$in": ["bob", "jake"] } }

array contains "bob":

{ "name" { "$has": "bob" } }

array does not contain "bob":

{ "name" { "$nhas": "bob" } }

When calling fields, such as name or age, or when calling arguments such as $eq$not$gt$gte$lt$lte$regex$has$nhas or $in, always wrap them in quotes so that you would have "name", this is proper JSON, and is required for your queries to work. It also makes them easier to read!

As you can see, there is a lot you can do with the query system, and this helps greatly extend what you can do with your Flybase app

Getting Data

You can also use the Get function to retrieve data, data handling is handled the same way as using the value event, but you can include instructions inside the call:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.get(function(snapshot) {
console.log( snapshot.value() );
},{l:1});

This will tell the app to return one record only, you can also include other instructions and queries inside it, we’ll cover the queries below. If you leave the options area blank, then you will return all records:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
ref.get(function(snapshot) {
snapshot.forEach( function( post ){
console.log( post.value() );
});
});

Optional parameters

  • {'q':{query}} – restrict results by the specified JSON query
  • {'c':true} – return the result count for this query
  • {'fo':true} – return a single document from the result set
  • {'s':[sort order]} – specify the order in which to sort each specified field (1- ascending; -1 – descending)
  • {'sk':[num results to skip]} – specify the number of results to skip in the result set; useful for paging
  • {'l':limit} – specify the limit for the number of results (default is 1000)

Examples using these parameters:

// Get a reference to our posts
const ref = new Flybase("74k8064f-cd6f-4c07-8baf-b1d241496eec", "web", "posts");
// "q" example - return all documents with "active" field of true:
const params = { q: { active: true } };
ref.get(function(snapshot) {
snapshot.forEach( function( post ){
console.log( post.value() );
});
},params);
// "fo" example - return a single document matching "active" field of true:
const params = { fo: true };
ref.get(function(snapshot) {
console.log( snapshot.value() );
},params);
// "s" example - return all documents sorted by "priority" ascending and "difficulty" descending:
const params = { s: {"priority": 1, "difficulty": -1} };
ref.get(function(snapshot) {
snapshot.forEach( function( post ){
console.log( post.value() );
});
},params);
// "sk" and "l" example - sort by "name" ascending and return 10 documents after skipping 20
const params = { s: {"name": 1},sk: 20,l: 10 };
ref.get(function(snapshot) {
snapshot.forEach( function( post ){
console.log( post.value );
});
},params);

Joining Data

You can also use a lookup to query multiple collections at once.

For example, let’s say we were building a chat system, and that chat system was set up so that chat messages were stored inside the messages collection and user info was stored inside the users collection, we’d want to display who posted what right?

const get_user_info = ( userId, cb ) => {
messagesRef.lookup(
userId,
[
'chat.userId',
'users._id'
],
function (jdata ){
cb( jdata );
});
}
messagesRef.on('value').then( function(data){
data.forEach( function( row ){
var row = row.value();
get_user_info( row._id, function( data ){
console.log( data.name + ": + data.message;
});
});
}

This would perform an initial query on the chat page

When using the lookup function, we pass the value to join data on, an array of collections with the field to join by and a callback or promise to handle the data.

The lookup function will return an object of data rather than the usual Flybase object, this is so you can display data faster and also because it’s returned as a single row and is meant to be read-only.

lookup was set up to make it handy for assembling data to display across multiple collections quickly and easily.

Now that we’ve covered retrieving data from Flybase, we’re ready for the next article on deleting data in Flybase.