You're viewing the legacy docs. They are deprecated as of May 18, 2016.
These docs are for version 2.4.2 and below of the Javascript SDK. Go to our current docs, or see our Web migration guide.

JavaScript Web Guide

Saving Data

In this document we'll cover the four methods for writing data to your Firebase database: set(), update(), push(), and our transaction feature.

Ways to Save Data

set( ) Write or replace data to a defined path, like messages/users/<username>
update( ) Update some of the keys for a defined path without replacing all of the data
push( ) Add to a list of data in the database. Every time you call push() your database generates a unique ID, like messages/users/<unique-user-id>/<username>
transaction( ) Use our transactions feature when working with complex data that could be corrupted by concurrent updates

Writing Data with set()

The basic database write operation is set() which saves new data to the specified database reference, replacing any existing data at that path. To understand set(), we'll build a simple blogging app. The data for our app will be stored at this database reference:

var ref = new Firebase("https://docs-examples.firebaseio.com/web/saving-data/fireblog");

Let's start by saving some user data. We'll store each user by a unique username, and we'll also store their full name and date of birth. Since each user will have a unique username, it makes sense to use set() here instead of push() since we already have the key and don't need to create one.

First, we'll create a database reference to our user data. Then we'll use set() to save a user object to the database with the user's username, full name, and birthday. We can pass set() a string, number, boolean, null, array or any JSON object. Passing null to set() will remove the data at the specified location. In this case we'll pass it an object:

var usersRef = ref.child("users");
usersRef.set({
  alanisawesome: {
    date_of_birth: "June 23, 1912",
    full_name: "Alan Turing"
  },
  gracehop: {
    date_of_birth: "December 9, 1906",
    full_name: "Grace Hopper"
  }
});

When a JSON object is saved to the database, the object properties are automatically mapped to database child locations in a nested fashion. Now if we navigate to the URL https://docs-examples.firebaseio.com/web/saving-data/fireblog/users/alanisawesome/full_name, we'll see the value "Alan Turing". You can also save data directly to a child location:

usersRef.child("alanisawesome").set({
  date_of_birth: "June 23, 1912",
  full_name: "Alan Turing"
});
usersRef.child("gracehop").set({
  date_of_birth: "December 9, 1906",
  full_name: "Grace Hopper"
});

The above two examples - writing both values at the same time as an object and writing them separately to child locations - will result in the same data being saved to your database:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper"
    }
  }
}

The first example will only trigger one event on clients that are watching the data, whereas the second example will trigger two. It is important to note that if data already existed at usersRef, the first approach would overwrite it, but the second method would only modify the value of each separate child node while leaving other children of usersRef unchanged.

Using set() will overwrite the data at the specified location, including any child nodes.

Updating Saved Data

If you want to write to multiple children of a database location at the same time without overwriting other child nodes, you can use the update() method as shown below:

var hopperRef = usersRef.child("gracehop");
hopperRef.update({
  "nickname": "Amazing Grace"
});

This will update Grace's data to include her nickname. If we had used set() here instead of update(), it would have deleted both full_name and date_of_birth from our hopperRef.

Firebase also supports multi-path updates. This means that update() can now update values at multiple locations in your Firebase database at the same time, a powerful feature which allows helps you denormalize your data. Using multi-path updates, we can add nicknames to both Grace and Alan at the same time:

usersRef.update({
  "alanisawesome/nickname": "Alan The Machine"
  "gracehop/nickname": "Amazing Grace"
});

After this update, both Alan and Grace have had their nicknames added:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

Note that trying to update objects by writing objects with the paths included will result in different behavior. Let's take a look at what happens if we instead try to update Grace and Alan this way:

usersRef.update({
  "alanisawesome": {
    "nickname": "Alan The Machine"
  },
  "gracehop": {
    "nickname": "Amazing Grace"
  }
});

This results in different behavior, namely overwriting the entire /users node:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}
Updating Nested Data

Given a single key path like alanisawesome, update() only updates data at the first child level, and any data passed in beyond the first child level is a treated as a set() operation. Multi-path behavior allows longer paths (like alanisawesome/nickname) to be used without overwriting data. This is why the first example differs from the second example.

Adding a Completion Callback

If you'd like to know when your data has been committed, you can add a completion callback. Both set() and update() take an optional completion callback that is called when the write has been committed to the database. If the call was unsuccessful for some reason, the callback will be passed an error object indicating why the failure occurred.

dataRef.set("I'm writing data", function(error) {
  if (error) {
    alert("Data could not be saved." + error);
  } else {
    alert("Data saved successfully.");
  }
});

Saving Lists of Data

When creating lists of data, it is important to keep in mind the multi-user nature of most applications and adjust your list structure accordingly. Expanding on our example above, let's add blog posts to our app. Your first instinct might be to use set() to store children with auto-incrementing integer indexes, like the following:

ANTIPATTERN: This is not a recommended practice
// NOT RECOMMENDED - use push() instead!
{
  "posts": {
    "0": {
      "author": "gracehop",
      "title": "Announcing COBOL, a New Programming Language"
 	  },
    "1": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
	  }
  }
}

If a user adds a new post it would be stored as /posts/2. This would work if only a single author were adding posts, but in our collaborative blogging application many users may add posts at the same time. If two authors write to /posts/2 simultaneously, then one of the posts would be deleted by the other.

To solve this, the Firebase JavaScript clients provide a push() function that generates a unique ID, or key, for each new child. By using unique child keys, several clients can add children to the same location at the same time without worrying about write conflicts.

var postsRef = ref.child("posts");

  var newPostRef = postsRef.push();
  newPostRef.set({
    author: "gracehop",
    title: "Announcing COBOL, a New Programming Language"
  });

  // we can also chain the two calls together
  postsRef.push().set({
    author: "alanisawesome",
    title: "The Turing Machine"
  });

The unique key is based on a timestamp, so list items will automatically be ordered chronologically. Because we generate a unique ID for each blog post, no write conflicts will occur if multiple users add a post at the same time. Our database data now looks like this:

{
  "posts": {
    "-JRHTHaIs-jNPLXOQivY": {
      "author": "gracehop",
      "title": "Announcing COBOL, a New Programming Language"
    },
    "-JRHTHaKuITFIhnj02kE": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

In JavaScript, the pattern of calling push() and then immediately calling set() is so common that we let you combine them by passing the data to be set directly to push() as follows:

// This is equivalent to the calls to push().set(...) above
  postsRef.push({
    author: "gracehop",
    title: "Announcing COBOL, a New Programming Language"
  });

Getting the Unique ID Generated by push()

Calling push() will return a reference to the new data path, which you can use to get the value of its ID or set data to it. The following code will result in the same data as the above example, but now we'll have access to the unique push ID that was generated:

// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();

// Get the unique ID generated by push()
var postID = newPostRef.key();

As you can see, calling key() on our push() reference gives us the value of the unique ID.

Interested in learning more about how push IDs are generated? Check out this blog post.

In the next section on Retrieving Data, we'll learn how to read this data from a Firebase database.

Saving Transactional Data

When working with complex data that could be corrupted by concurrent modifications, such as incremental counters, we provide a transaction operation. You give this operation two arguments: an update function and an optional completion callback. The update function takes the current state of the data as an argument and will return the new desired state you would like to write. For example, if we wanted to increment the number of upvotes on a specific blog post, we would write a transaction like the following:

var upvotesRef = new Firebase('https://docs-examples.firebaseio.com/android/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction(function (current_value) {
  return (current_value || 0) + 1;
});

We use current_value || 0 to see if the counter is null or hasn't been incremented yet, since transactions can be called with null if no default value was written.

If the above code had been run without a transaction function and two clients attempted to increment it simultaneously, they would both write 1 as the new value, resulting in one increment instead of two.

Transaction Function is Called Multiple Times

transaction() will be called multiple times and must be able to handle null data. Even if there is existing data in your database it may not be locally cached when the transaction function is run.

Details on transactions can be found in our API docs.

Network Connectivity and Offline Writes

If a client loses network connection, your app will continue functioning correctly.

Every Firebase client maintains its own internal version of any active data. When data is written, it is written to this local version first. The client then synchronizes that data with the database and with other clients on a 'best-effort' basis.

As a result, all writes to the database will trigger local events immediately, before any data has even been written to the database. This means that when we write an application using Firebase, our app will remain responsive regardless of network latency or Internet connectivity.

Once connectivity is reestablished, we'll receive the appropriate set of events so that the client "catches up" with the current server state, without having to write any custom code.

Securing Your Data

Firebase databases have a security language that lets you define which users have read and write access to different nodes of your data. You can read more about it in Securing Your App.

  1. 1

    Next

    Installation & Setup

  2. 2

    Next

    Understanding Data

  3. 3

    Next

    Saving Data

  4. 4

    Next

    Retrieving Data

  5. 5

    Next

    Structuring Data

  6. 6

    Next

    Understanding Security

  7. 7

    Next

    User Authentication

  8. 8

    Next

    Offline Capabilities

  9. 9

    Next

    Deploying Your App