Realtime Database
To start using the Realtime Database package within your project, import it at the top of your project files:
Before using Realtime Database, you must first have ensured you have initialized FlutterFire.
To create a new Database instance, call the instance
getter on FirebaseDatabase
:
By default, this allows you to interact with the Realtime Database using the default Firebase App used whilst installing FlutterFire on your
platform. If however you'd like to use it with a secondary Firebase App, use the instanceFor
method:
#
Creating a referenceRealtime Database stores data as JSON, however enables you to access nodes of the data via a DatabaseReference
.
For example, if your data is stored as the following:
You can create a reference to a node by providing a path:
users
: Creates a reference to the entire "users" objectusers/123
: Creates a reference to the "123" user objectusers/123/name
: Creates a reference to a property (with the value of "John")
To create a new DatabaseReference
, pass the path to the ref
method:
If you do not provide a path, the reference will point to the root of your database.
The DatabaseReference
provides some useful utilities to access sub-nodes, access the parent
(if one exists) and modify data.
#
Read dataThe Realtime Database allows you to read data either once, or be notified on any changes to the node and it's children.
To read the data once, call the once
method on a DatabaseReference
:
The result of a read is a DatabaseEvent
. This contains a DataSnapshot
of the data at the location of the reference,
along with some additional metadata such as the reference key or whether the node exists in your database.
If you'd instead like to subscribe to realtime updates, the onValue
method returns a Stream
:
Anytime data within the users/123
node changes, the Stream will fire a new event.
#
QueryingWithout specifying any query constraints, reading data will return all data within the node. If you wish to query your node for a subset of data, the package provides utilities to do so. For example, we could choose to order our data by an "age" property, and limit the returns returned:
Alternatively we could instead return users between certain ages by using startAt
and endAt
:
#
Modifying dataWhen modifying data we can either set
the data (overwrite everything which exists at a node) or
update
specific parts of a node.
To set data, call the set
method on a DatabaseReference
:
To update data, provide a Map
where the keys point to specific nodes of the parent DatabaseReference
:
The update
method accepts a sub-path to nodes, allowing you to update multiple nodes on the database at
once:
#
Removing dataTo remove data from your database, call the remove
method (or set
with a null
value):
Removing a node will delete all data, including nested objects.
#
Running transactionsWhen working with data that could be corrupted by concurrent modifications, such as incremental
counters, you can use a transaction. A TransactionHandler
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, your update function is called again with the new
current value, and the write is retried.
By default, events are raised each time the transaction update function runs. So if it is run
multiple times, you may see intermediate states. You can set applyLocally
to false to suppress these
intermediate states and instead wait until the transaction has completed before events are raised:
The result of a transaction is a TransactionResult
, which contains information such as whether
the transaction was committed, and the new snapshot:
#
Aborting a transactionIf you wish to safely abort a transaction from executing, you can throw a AbortTransactionException
:
#
Atomic server-side operationsAlternatively we're able to execute atomic operations on the server to ensure there is no chance of conflicts or out-of-sync updates.
For example, we can increment an age and set a timestamp on the server, rather than the client by using the
ServerValue
class:
#
Offline CapabilitiesFirebase Database clients provide simple primitives that you can use to write to the database when a client disconnects from the Firebase Database servers. These updates occur whether the client disconnects cleanly or not, so you can rely on them to clean up data even if a connection is dropped or a client crashes. All write operations, including setting, updating, and removing, can be performed upon a disconnection.
First, create a new OnDisconnect
instance on a DatabaseReference
:
Next apply any operations which should trigger when the user disconnects. For example, we can easily create a presence system by storing a boolean value on a user if they are online, and remove it if they go offline:
The OnDisconnect
instance supports set
, setWithPriority
, remove
and update
operations.
You can remove any committed operations at anytime by calling the cancel
method:
#
Emulator UsageIf you are using the local Firestore emulators,
then it is possible to connect to this using the useDatabaseEmulator
method. Ensure you pass the correct port on which the Firebase emulator is running on.
Ensure you have enabled network connections to the emulators in your apps following the emulator usage instructions in the general FlutterFire installation notes for each operating system.