Realtime Database (Java)

Firebase Realtime Database is Firebase's original cloud database product, predating Cloud Firestore from the previous lesson. Instead of collections and documents, it stores everything in one giant JSON tree — the whole database is, conceptually, a single nested object that every connected client reads and writes pieces of.

recipebox-app (root) └─ recipes ├─ -NcX1a2B3 (a recipe's push-generated key) │ ├─ title: "Grandma's Chicken Curry" │ ├─ category: "Dinner" │ └─ ownerUid: "uid_abc123" └─ -NcX1a9Z7 ├─ title: "Weekend Pancakes" └─ ownerUid: "uid_xyz789"
Every recipe is just another branch under recipes in this one tree — there is no separate "collection" concept the way Firestore has.

Realtime Database vs Firestore: An Honest Comparison

ConcernRealtime DatabaseCloud Firestore
Data modelOne large JSON treeCollections of documents
QueryingLimited — hard to combine multiple filtersRich queries: whereEqualTo, orderBy, compound filters
Scaling & structureGets awkward as data grows and nests deeperScales cleanly with flatter, indexable documents
LatencyExtremely low — very fast updatesFast, though typically a touch behind Realtime DB
Google's guidanceStill supported, maintenance mode mindsetThe recommended default for new projects

Writing Data with setValue()

A DatabaseReference points at a location in the tree, the same way a StorageReference will point at a file location in a later lesson. .setValue() writes (or completely overwrites) whatever is at that location.

DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();

Recipe recipe = new Recipe();
recipe.title = "Weekend Pancakes";
recipe.category = "Breakfast";
recipe.prepMinutes = 15;
recipe.ownerUid = FirebaseAuth.getInstance().getCurrentUser().getUid();

String recipeId = databaseReference.child("recipes").push().getKey();

databaseReference.child("recipes").child(recipeId).setValue(recipe)
    .addOnSuccessListener(unused ->
        Log.d("RecipeBox", "Recipe saved at recipes/" + recipeId))
    .addOnFailureListener(e ->
        Log.e("RecipeBox", "Save failed", e));
Explanation:
  • .child("recipes") descends into the recipes branch of the tree; .push() generates a unique, chronologically-sortable key for the new recipe.
  • .child(recipeId).setValue(recipe) writes the full Recipe object as JSON at that exact path.

Reading Data with ValueEventListener

Reading works through a listener interface rather than a one-shot call: onDataChange() fires immediately with the current data, and again every time it changes — conceptually similar to Firestore's addSnapshotListener(), just with a different API shape.

databaseReference.child("recipes").addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        List<Recipe> recipes = new ArrayList<>();
        for (DataSnapshot child : snapshot.getChildren()) {
            Recipe recipe = child.getValue(Recipe.class);
            recipes.add(recipe);
        }
        adapter.submitList(recipes);
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
        Log.e("RecipeBox", "Read failed", error.toException());
    }
});
Explanation:
  • snapshot.getChildren() iterates every recipe currently stored under the recipes branch.
  • child.getValue(Recipe.class) converts one branch's JSON back into a Recipe object.
  • onCancelled() fires for permission errors — for example, if Security Rules reject the read.

Which One Should RecipeBox Use?

Starting a new project? Choose Firestore, covered in the previous lesson — its richer querying and cleaner scaling make it the safer long-term default, and it's what Google itself now points new developers toward.

Already maintaining an app built on Realtime Database? There's rarely a compelling reason to migrate an existing, working data model just to switch products.

Need extremely low-latency presence detection (e.g., "is this user online right now")? Realtime Database's connection-state features remain a genuine, specific strength.

Between Firestore and Realtime Database, RecipeBox now has a solid way to store and sync recipe data. The next lesson turns to Cloud Messaging (FCM), so RecipeBox can actively notify a user — for example, when a new recipe is added to a shared family cookbook.