Skip to content
This repository has been archived by the owner on May 17, 2022. It is now read-only.

B.4 Save Data

MyFlashLabs edited this page Mar 9, 2017 · 3 revisions

There are four methods for writing data to the Firebase Realtime Database:

  • setValue() Write or replace data to a defined path, such as users/user-id/username.
  • push() Add to a list of data. Every time you call push(), Firebase generates a unique ID, such as user-posts/user-id/unique-post-id.
  • updateChildren() Update some of the keys for a defined path without replacing all of the data.
  • runTransaction() Update complex data that could be corrupted by concurrent updates.

Note: By default, read and write access to your database is restricted so only authenticated users can read or write data. To get started without setting up Authentication, you can configure your rules for public access. This does make your database open to anyone, even people not using your app, so be sure to restrict your database again when you set up authentication.

Get a DBReference

To write data to the Database, you need an instance of DBReference by calling DB.getReference

// make a reference to the root of your database
var myRef:DBReference = DB.getReference();

// you may also make references to child nodes like:
// var myRef:DBReference = DB.getReference("branch1/subBranch2");

Basic write operations

For basic write operations, you can use setValue() to save data to a specified reference, replacing any existing data at that path. You can use this method to pass types that correspond to the available JSON types as follows:

  • String
  • Number
  • Boolean
  • Object
  • Array

For example, if you have an app with a basic user profile, your user object might look as follows:

var user:Object = {};
user.username = "myflashlabs";
user.email = "[email protected]";

You can add a user with setValue() as follows:

myRef.child("users").child("userId").setValue(user);

Using setValue() in this way overwrites data at the specified location, including any child nodes. However, you can still update a child without rewriting the entire object. If you want to allow users to update their profiles you could update the username as follows:

myRef.child("users").child("userId").child("username").setValue(name);

Append to a list of data

Use the push() method to append data to a list in multiuser applications. The push() method generates a unique ID every time a new child is added to the specified Firebase reference. By using these auto-generated keys for each new element in the list, several clients can add children to the same location at the same time without write conflicts. The unique ID generated by push() is based on a timestamp, so list items are automatically ordered chronologically.

You can use the reference to the new data returned by the push() method to get the value of the child's auto-generated key or set data for the child. Calling the key property on a push() reference returns the value of the auto-generated key. You can use these auto-generated keys to simplify flattening your data structure.

Update specific fields

To simultaneously write to specific children of a node without overwriting other child nodes, use the updateChildren() method.

When calling updateChildren(), you can update lower-level child values by specifying a path for the key. If data is stored in multiple locations to scale better, you can update all instances of that data using data fan-out. For example, a social blogging app might have a post object like this:

var post:Object = {};
post.uid = uid;
post.author = author;
post.title = title;
post.body = body;
post.starCount = 0;

To create a post and simultaneously update it to the recent activity feed and the posting user's activity feed, the blogging application uses code like this:

function writeNewPost($userId:String, $username:String, $title:String, $body:String):void
{
	// Create new post at /user-posts/$userid/$postid and at /posts/$postid simultaneously
	var key:String = myRef.child("posts").push().key;
	
	var map:Object = {};
	map["/posts/" + key] = post;
	map["/user-posts/" + $userId + "/" + key] = post;
	
	myRef.updateChildren(map);
}

This example uses push() to create a post in the node containing posts for all users at /posts/$postid and simultaneously retrieve the key using the key property. The key can then be used to create a second entry in the user's posts at /user-posts/$userid/$postid.

Using these paths, you can perform simultaneous updates to multiple locations in the JSON tree with a single call to updateChildren(), such as how this example creates the new post in both locations. Simultaneous updates made this way are atomic: either all updates succeed or all updates fail.

Delete data

The simplest way to delete data is to call removeValue() on a reference to the location of that data.

You can also delete by specifying an empty String "" as the value for updateChildren() or setValue(). You can use this technique with updateChildren() to delete multiple children in a single API call.

Add Listeners for the operations

To know when your data is committed to the Firebase Realtime Database server, you can add a completion listener so you will know if your data has been commited successfully or failed.

myRef.addEventListener(DBEvents.SET_VALUE_SUCCESS, onSetValueSuccess);
myRef.addEventListener(DBEvents.SET_VALUE_FAILURE, onSetValueFailure);

myRef.addEventListener(DBEvents.UPDATE_CHILDREN_SUCCESS, onUpdateChildrenSuccess);
myRef.addEventListener(DBEvents.UPDATE_CHILDREN_FAILURE, onUpdateChildrenFailure);

Save data as transactions

When working with data that could be corrupted by concurrent modifications, such as incremental counters, you can use a transaction operation. When starting a transaction operation, you should listen to three events as follow:

myRef.addEventListener(DBEvents.TRANSACTION_PROGRESS, onTransactionProgress);
myRef.addEventListener(DBEvents.TRANSACTION_COMPLETE, onTransactionSuccess);
myRef.addEventListener(DBEvents.TRANSACTION_FAILURE, onTransactionFailure);

The onTransactionProgress function takes the current state of the data as an argument and returns the new desired state you would like to write. If another client writes to the location before your new value is successfully written, the onTransactionProgress function is called again with the new current value, and the write is retried.

For instance, if you have a counter node in your database and you wish users to add one value to it's current value by hitting a button, the below sample shows you how to manage this:

function onButtonClicked(e:MouseEvent):void
{
	if (!refTransaction.runTransaction())
	{
		trace("transaction is currently busy, try again in a few seconds.");
		// setTimeout(onButtonClicked, 500, e);
	}
}

function onTransactionProgress(e:DBEvents):void
{
	if 		(e.mutableData.value is String) 	trace("TransactionProgress current value (String) = " + e.mutableData.value);
	else if (e.mutableData.value is Number) 	trace("TransactionProgress current value (Number) = " + e.mutableData.value);
	else if (e.mutableData.value is Boolean) 	trace("TransactionProgress current value (Boolean) = " + e.mutableData.value);
	else if (e.mutableData.value is Array) 		trace("TransactionProgress current value (Array) = " + JSON.stringify(e.mutableData.value));
	else 										trace("TransactionProgress current value (Object) = " + JSON.stringify(e.mutableData.value));
	
	trace("mutableData.key = " + e.mutableData.key);
	
	// get the current value on server
	if (e.mutableData.value) 
	{
		// increment the current value by one
		e.mutableData.setValue(e.mutableData.value + 1);
	}
	else 
	{
		// if current value is not available, let's be the first one who writes it!
		e.mutableData.setValue(1);
	}
	
	// You must call either of these methods so the operation can continue its job based on your decision
	e.mutableData.continueSuccess();
	//e.mutableData.continueAbort();
}

function onTransactionFailure(e:DBEvents):void
{
	trace("onTransaction Done Failure: " + e.msg);
}

function onTransactionSuccess(e:DBEvents):void
{
	trace("-------------------");
	
	if (e.dataSnapshot.exists)
	{
		if 		(e.dataSnapshot.value is String) 	trace("onTransactionSuccess value (String) = " + e.dataSnapshot.value);
		else if (e.dataSnapshot.value is Number) 	trace("onTransactionSuccess value (Number) = " + e.dataSnapshot.value);
		else if (e.dataSnapshot.value is Boolean) 	trace("onTransactionSuccess value (Boolean) = " + e.dataSnapshot.value);
		else if (e.dataSnapshot.value is Array) 	trace("onTransactionSuccess value (Array) = " + JSON.stringify(e.dataSnapshot.value));
		else 										trace("onTransactionSuccess value (Object) = " + JSON.stringify(e.dataSnapshot.value));
	}
	
	trace("-------------------");
}

Using a transaction prevents star counts from being incorrect if multiple users star the same post at the same time or the client had stale data. If the transaction is rejected, the server returns the current value to the client, which runs the transaction again with the updated value. This repeats until the transaction is accepted or too many attempts have been made.

Note: Because onTransactionProgress is called multiple times, it must be able to handle null data. Even if there is existing data in your remote database, it may not be locally cached when the transaction function is run, resulting in null for the initial value.

Write data offline

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

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

As a result, all writes to the database trigger local events immediately, before any data is written to the server. This means your app remains responsive regardless of network latency or connectivity.

Once connectivity is reestablished, your app receives the appropriate set of events so that the client syncs with the current server state, without having to write any custom code.

Introduction to Firebase ANEs collection for Adobe Air apps


Get Started with Firebase Core in AIR

  1. Prerequisites
  2. Add Firebase to your app
  3. Add the Firebase SDK
  4. Init Firebase Core
  5. Available ANEs
  6. Managing Firebase iid

Get Started with Analytics

  1. Add Analytics ANE
  2. Init Analytics ANE
  3. Log Events
  4. Set User Properties

Get Started with Crashlytics

  1. Add Crashlytics ANE
  2. Test Your Implementation
  3. Customize Crash Reports
  4. Upload .dSYM for iOS apps

Get Started with DynamicLinks

  1. Add DynamicLinks ANE
  2. Init DynamicLinks ANE
  3. Create DynamicLinks
  4. Receive DynamicLinks
  5. View Analytics

Get Started with Authentication

  1. Add Authentication
  2. Init Authentication
  3. Manage Users
  4. Phone Number
  5. Custom Auth
  6. Anonymous Auth
  7. State in Email Actions
  8. Email Link Authentication

Get Started with FCM + OneSignal

  1. Add FCM ANE
  2. Init FCM ANE
  3. Send Your 1st Message
  4. Send Msg to Topics
  5. Understanding FCM Messages
  6. init OneSignal

Get Started with Firestore

  1. Add Firestore
  2. Init Firestore
  3. Add Data
  4. Transactions & Batches
  5. Delete Data
  6. Manage the Console
  7. Get Data
  8. Get Realtime Updates
  9. Simple and Compound
  10. Order and Limit Data
  11. Paginate Data
  12. Manage Indexes
  13. Secure Data
  14. Offline Data
  15. Where to Go From Here

Get Started with Realtime Database

  1. Add Realtime Database
  2. Init Realtime Database
  3. Structure Your Database
  4. Save Data
  5. Retrieve Data
  6. Enable Offline Capabilities

Get Started with Remote Config

  1. Parameters and Conditions
  2. Add Remote Config
  3. Init Remote Config

Get Started with Performance

  1. Add Performance ANE
  2. Init & Start Monitoring

Get Started with Storage

  1. Add Storage ANE
  2. Init Storage ANE
  3. Upload Files to Storage
  4. Download Files to Air
  5. Use File Metadata
  6. Delete Files

Get Started with Functions

  1. Write & Deploy Functions
  2. Add Functions ANE
  3. Init Functions
Clone this wiki locally