22 Using Database SDK

This chapter demonstrates how to perform database operations using Oracle Backend for Firebase SDKs across multiple platforms. The examples are grouped by SDK type and cover common tasks such as creating, reading, updating, and deleting documents, as well as querying collections.

22.1 Supported Features

  • Document-based storage

  • Real-time listeners

  • Aggregation queries

  • Transactions and batch writes

  • Duality views for relational mapping

22.2 Writing Data: Set Document Examples

Set Document (Merge: false)

This operation creates or overwrites a document at a specific path. If the document exists, all fields are replaced.

import { doc, setDoc } from "fusabase/oracledb";

 // 1 Create/Update user document
  await setDoc(doc(db, "users", "Scott"), {
    displayName: "Scott",
    photoURL: user.photoURL || null,
  }, { merge: false }); 

  // 2 Create a recipe subcollection document under this user
  await setDoc(doc(db, "users", "Scott", "recipes", "Cookies"), {
    uuid: "Scott",
    title: "Chocolate Chip Cookies",
    ingredients:"2 cups flour,1 cup sugar,1/2 cup chocolate chips",
    steps: ["Mix ingredients", "Bake for 15 min"],
    category: "Dessert",
    difficulty: "Easy",
    tags: ["sweet", "baking"],
    avgRating: 0,
    photoRefs: []
  });
// 1 Create/Update user document
await db
  .collection("users")
  .doc("Scott")
  .set(
    {
      displayName: "Scott",
      photoURL: user.photoURL || null,
    },
    { merge: false }
  );

// 2 Create a recipe subcollection document under this user
await db
  .collection("users")
  .doc("Scott")
  .collection("recipes")
  .doc("Cookies")
  .set({
    uuid: "Scott",
    title: "Chocolate Chip Cookies",
    ingredients: "2 cups flour,1 cup sugar,1/2 cup chocolate chips",
    steps: ["Mix ingredients", "Bake for 15 min"],
    category: "Dessert",
    difficulty: "Easy",
    tags: ["sweet", "baking"],
    avgRating: 0,
    photoRefs: [],
  });
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

// 1 Create/Update user document
Map<String, Object> user = new HashMap<>();
user.put("displayName", "Scott");
user.put("photoURL", null); // or user.getPhotoUrl()

db.collection("users").document("Scott")
        .set(user);

// 2 Create recipe subcollection document
Map<String, Object> recipe = new HashMap<>();
recipe.put("uuid", "Scott");
recipe.put("title", "Chocolate Chip Cookies");
recipe.put("ingredients", "2 cups flour,1 cup sugar,1/2 cup chocolate chips");
recipe.put("steps", Arrays.asList("Mix ingredients", "Bake for 15 min"));
recipe.put("category", "Dessert");
recipe.put("difficulty", "Easy");
recipe.put("tags", Arrays.asList("sweet", "baking"));
recipe.put("avgRating", 0);
recipe.put("photoRefs", new ArrayList<>());

db.collection("users").document("Scott")
        .collection("recipes").document("Cookies")
        .set(recipe);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

// 1 Create / Update user document
db.collection("users").document("Scott").setData(
    [
        "displayName": "Scott",
        "photoURL": user.photoURL ?? NSNull()
    ],
    merge: false
)

// 2 Create a recipe subcollection document under this user
db.collection("users")
  .document("Scott")
  .collection("recipes")
  .document("Cookies")
  .setData([
      "uuid": "Scott",
      "title": "Chocolate Chip Cookies",
      "ingredients": "2 cups flour,1 cup sugar,1/2 cup chocolate chips",
      "steps": ["Mix ingredients", "Bake for 15 min"],
      "category": "Dessert",
      "difficulty": "Easy",
      "tags": ["sweet", "baking"],
      "avgRating": 0,
      "photoRefs": []
  ])
import 'package:fusabase/oracledb.dart';


// 1 Create / Update user document
await db.collection('users').doc('Scott').set(
  {
    'displayName': 'Scott',
    'photoURL': user.photoURL ?? null,
  },
  SetOptions(merge: false),
);
// 2 Create a recipe subcollection document under this user
await db
.collection('users')
.doc('Scott')
.collection('recipes')
.doc('Cookies')
.set({
'uuid': 'Scott',
'title': 'Chocolate Chip Cookies',
'ingredients': '2 cups flour,1 cup sugar,1/2 cup chocolate chips',
'steps': ['Mix ingredients', 'Bake for 15 min'],
'category': 'Dessert',
'difficulty': 'Easy',
'tags': ['sweet', 'baking'],
'avgRating': 0,
'photoRefs': [],
});

Set Document (Merge: true)

This operation updates only the specified fields in an existing document. Unspecified fields remain unchanged.

import { doc, setDoc } from "fusabase/oracledb"; 

 // Update existing recipe subcollection document under this user
  await setDoc(doc(db, "users", "Scott", "recipes", "Cookies"), {
    title: "Rich Chocolate Chip Cookies",
    ingredients:"2 cups flour,1 cup sugar,2 cup chocolate chips",
  },{ merge: true });
db.collection("users")
  .doc("Scott")
  .collection("recipes")
  .doc("Cookies")
  .set(
    {
      title: "Rich Chocolate Chip Cookies",
      ingredients: "2 cups flour,1 cup sugar,2 cup chocolate chips",
    },
    { merge: true }
  )
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.SetOptions;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;

Map<String, Object> updates = new HashMap<>();
updates.put("title", "Rich Chocolate Chip Cookies");
updates.put("ingredients", "2 cups flour,1 cup sugar,2 cup chocolate chips");

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.collection("users")
  .document("Scott")
  .collection("recipes")
  .document("Cookies")
  .set(updates, SetOptions.merge())
  .addOnSuccessListener(aVoid -> Log.d("Oracledb", "Recipe updated"))
  .addOnFailureListener(e -> Log.w("Oracledb", "Error updating recipe", e));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("users")
  .document("Scott")
  .collection("recipes")
  .document("Cookies")
  .setData(
      [
          "title": "Rich Chocolate Chip Cookies",
          "ingredients": "2 cups flour,1 cup sugar,2 cup chocolate chips"
      ],
      merge: true
  )
// Update existing recipe document (merge = true)
await db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .doc('Cookies')
    .set(
  {
    'title': 'Rich Chocolate Chip Cookies',
    'ingredients': '2 cups flour,1 cup sugar,2 cup chocolate chips',
  },
  SetOptions(merge: true),
);

Using Supported Field Attributes

This operation demonstrates advanced field operations like timestamping, incrementing, array manipulation, and field deletion.

import {doc, setDoc, serverTimestamp, increment, deleteField} from "fusabase/oracledb";

// Base reference
const recipeRef = doc(db, "users", "Scott", "recipes", "Cookies");

// Create a recipe with server timestamps
await setDoc(recipeRef, {
  title: "Chocolate Chip Cookies",
  ingredients: "2 cups flour,1 cup sugar,2 cups chocolate chips",
  tags: arrayUnion("dessert"),
  createdAt: serverTimestamp(),
  updatedAt: serverTimestamp(),
  views: increment(1),
  notest : deleteField()
});
import oracledb from "fusabase/oracledb";


db.collection("users").document("Scott")
  .collection("recipes").document("Cookies")
  .set({
    "title": "Chocolate Chip Cookies",
    "ingredients": "2 cups flour,1 cup sugar,2 cups chocolate chips",
    "tags":  oracledb.FieldValue.arrayUnion("desert"),
    "createdAt": oracledb.FieldValue.serverTimestamp(),
    "updatedAt": oracledb.FieldValue.serverTimestamp(),
    "views": oracledb.FieldValue.increment(1),
    "notes" : oracledb.FieldValue.delete()
}) 
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.SetOptions;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

Map<String, Object> recipe = new HashMap<>();
recipe.put("title", "Chocolate Chip Cookies");
recipe.put("ingredients", "2 cups flour,1 cup sugar,2 cups chocolate chips");
recipe.put("tags", FieldValue.arrayUnion("desert"));
recipe.put("createdAt", FieldValue.serverTimestamp());
recipe.put("updatedAt", FieldValue.serverTimestamp());
recipe.put("views", FieldValue.increment(1));
recipe.put("notes",FieldValue.delete());

db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .set(recipe, SetOptions.merge());
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let recipeRef = db
    .collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")

// Create a recipe with server timestamps and FieldValue operations
recipeRef.setData([
    "title": "Chocolate Chip Cookies",
    "ingredients": "2 cups flour,1 cup sugar,2 cups chocolate chips",
    "tags": FieldValue.arrayUnion(["dessert"]),
    "createdAt": FieldValue.serverTimestamp(),
    "updatedAt": FieldValue.serverTimestamp(),
    "views": FieldValue.increment(Int64(1)),
    "notest": FieldValue.delete()
])
// Base reference
final DocumentReference recipeRef = db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .doc('Cookies');

// Create a recipe with server timestamps and FieldValue operations
await recipeRef.set({
  'title': 'Chocolate Chip Cookies',
  'ingredients': '2 cups flour,1 cup sugar,2 cups chocolate chips',
  'tags': FieldValue.arrayUnion(['dessert']),
  'createdAt': FieldValue.serverTimestamp(),
  'updatedAt': FieldValue.serverTimestamp(),
  'views': FieldValue.increment(1),
  'notest': FieldValue.delete(),
});

Set servertimestamp for Document Field

import {doc, setDoc, serverTimestamp, increment, deleteField} from "fusabase/oracledb";

// Base reference
const userRef = doc(db, "users", "Scott");

// Create a recipe with server timestamps
await setDoc( userRef , {
  name: "John",
  createdAt: serverTimestamp(),
});
import oracledb from "fusabase-ns/oracledb";

await db.collection("users").document("Scott")
  .set({
    name: "John",
    createdAt: oracledb.FieldValue.serverTimestamp()
}) 
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import java.util.HashMap;
import java.util.Map;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

Map<String, Object> data = new HashMap<>();
data.put("name", "John");
data.put("createdAt", FieldValue.serverTimestamp());

// Set document with server timestamp
db.collection("users").document("Scott").set(data);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

var data: [String: Any] = [:]
data["name"] = "John"
data["createdAt"] = FieldValue.serverTimestamp()

// Set document with server timestamp
db.collection("users").document("Scott").setData(data)
// Base reference
final DocumentReference userRef = db
    .collection('users')
    .doc('Scott');

await userRef.set({
  "name": "John",
  "createdAt": FieldValue.serverTimestamp()
});

Update Specific Field within Nested Object

import {doc, updateDoc} from "fusabase/oracledb";

// Base reference
const userRef = doc(db, "users", "Scott");

await updateDoc(recipeRef, {
  "profile.city": "Mumbai"
});
import oracledb from "fusabase-ns/oracledb";

await db.collection("users").document("Scott")
  .update({
    "profile.city": "Mumbai"
}) 
import com.oracle.mobile.fusabase.FusabaseApp;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;

FusabaseOracledb db = FusabaseOracledb.oracledb();

db.collection("users").document("Scott").update("profile.city", "Mumbai");
import FusabaseOracledb
let db = FusabaseOracledb.oracledb()

db.collection("users").document("Scott").updateData(["profile.city": "Mumbai"])
// Base reference
final DocumentReference userRef = db
    .collection('users')
    .doc('Scott');

await userRef.update({
  "profile.city": "Mumbai"
});

Add Document with Different Data Types

import {doc, setDoc, serverTimestamp} from "fusabase/oracledb";

// Base reference
const pRef = doc(db, "products", "lap");

// 1 Create a recipe with server timestamps
await setDoc(pRef, {
  name: "Laptop",
  price: 45000,
  available: true,
  tags: ["electronics", "computer"],
  specs: {
    ram: "16GB",
    storage: "512GB"
  },
  createdAt: serverTimestamp()
});
import oracledb from "fusabase-ns/oracledb";

await db.collection("products").document("lap")
  .set({
    name: "Laptop",
    price: 45000,
    available: true,
    tags: ["electronics", "computer"],
    specs: {
      ram: "16GB",
      storage: "512GB"
    },
    createdAt: oracledb.FieldValue.serverTimestamp()
}, merge: true) 
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import com.oracle.mobile.fusabase.oracledb.DocumentReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

DocumentReference pRef = db.collection("products").document("lap");

Map<String, Object> productData = new HashMap<>();
productData.put("name", "Laptop");
productData.put("price", 45000);
productData.put("available", true);
productData.put("tags", Arrays.asList("electronics", "computer"));

Map<String, Object> specs = new HashMap<>();
specs.put("ram", "16GB");
specs.put("storage", "512GB");
productData.put("specs", specs);

productData.put("createdAt", FieldValue.serverTimestamp());

await pRef.set(productData);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()
let pRef = db.collection("products").document("lap")

pRef.setData([
    "name": "Laptop",
    "price": 45000,
    "available": true,
    "tags": ["electronics", "computer"],
    "specs": [
        "ram": "16GB",
        "storage": "512GB"
    ],
    "createdAt": FieldValue.serverTimestamp()
])
// Base reference
final DocumentReference pRef = db
    .collection('products')
    .doc('lap');

// Create a recipe with server timestamps and FieldValue operations
await pRef.set({
  "name": "Laptop",
  "price": 45000,
  "available": true,
  "tags": ["electronics", "computer"],
  "specs": {
    "ram": "16GB",
    "storage": "512GB"
  },
  "createdAt": FieldValue.serverTimestamp(),
});

Create a Collection with setdoc

import {doc, setDoc} from "fusabase/oracledb";

// Base reference
const oRef = doc(db, "orders", "order1");

// Create a recipe with server timestamps
await setDoc(oRef, {
  orderId: "ORD123",
  amount: 1200,
  status: "pending"
});
import oracledb from "fusabase-ns/oracledb";

await db.collection("orders").document("order1")
  .set({
    orderId: "ORD123",
    amount: 1200,
    status: "pending"
}) 
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

Map<String, Object> orderData = new HashMap<>();
orderData.put("orderId", "ORD123");
orderData.put("amount", 1200);
orderData.put("status", "pending");

await db.collection("orders").document("order1").set(orderData); 
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("orders").document("order1")
    .setData([
        "orderId": "ORD123", 
        "amount": 1200,
        "status": "pending"
    ])
// Base reference
final DocumentReference oRef = db
    .collection('orders')
    .doc('order1');

// Create a recipe with server timestamps and FieldValue operations
await oRef.set({
  orderId: "ORD123",
  amount: 1200,
  status: "pending"
});

Write Data using FieldPath

import {doc, updateDoc, FieldPath} from "fusabase/oracledb";

await updateDoc(doc(db, "users", "user1"), {
  [new FieldPath("User Profile", "Home City")]: "Mumbai"
});
import oracledb from "fusabase-ns/oracledb";


db.collection("users").doc("user1").update({
  [new oracledb.FieldPath("User Profile", "Home City")]: "Mumbai"
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.FieldPath;

FusabaseOracledb db = FusabaseOracledb.getInstance();

FieldPath fieldPath = FieldPath.of("User Profile", "Home City");db.collection("users").document("user1").update(fieldPath, "Mumbai");
import FusabaseOracledblet db = FusabaseOracledb.oracledb()

db.collection("users").document("user1")
.updateData([
FieldPath(["User Profile", "Home City"]): "Mumbai"
])
db.collection("users").doc("user1").update({
  FieldPath(["User Profile", "Home City"]): "Mumbai"
});

22.2.1 Writing Data: Add Document Examples

Creating a New Document (Auto-generated ID) within a Collection

This operation adds a new document to a subcollection with a system-generated ID. This operation is useful when you don’t want to manually assign IDs.

import {collection, addDoc, serverTimestamp} from "fusabase/oracledb";

// Reference to the notes subcollection
const notesRef = collection(db, "users", "Scott", "recipes", "Cookies", "notes");

// Add a new note document
await addDoc(notesRef, {
  uuid: "Scott", 
  content: {
    "step1": "Try adding a pinch of sea salt for balance.",
    "step2" : "Add extra chocolate chips"    }  createdAt: serverTimestamp()
});
// Reference to the notes subcollection
const notesRef = db.collection("users").doc("Scott").collection("recipes").doc("Cookies").collection("notes");

// Add a new note document
notesRef.add({
  uuid: "Scott", 
  content: {
    "step1": "Try adding a pinch of sea salt for balance.",
    "step2" : "Add extra chocolate chips"
    }
  createdAt: oracledb.FieldValue.serverTimestamp()
})
import com.oracle.mobile.fusabase.oracledb.CollectionReference;
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

CollectionReference notesRef = db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes");


// Create the note content with multiple steps
Map<String, Object> content = new HashMap<>();
content.put("step1", "Try adding a pinch of sea salt for balance.");
content.put("step2", "Add extra chocolate chips");

// Create the new note
Map<String, Object> note = new HashMap<>();
note.put("uuid", "Scott");
note.put("content", content);
note.put("createdAt", FieldValue.serverTimestamp());

// Add the note to the subcollection
notesRef.add(note);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let notesRef = db
    .collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")

// Add a new note document (auto-generated ID)
notesRef.addDocument(data: [
    "uuid": "Scott",
    "content": [
        "step1": "Try adding a pinch of sea salt for balance.",
        "step2": "Add extra chocolate chips"
    ],
    "createdAt": FieldValue.serverTimestamp()
])
// Reference to the notes subcollection
final CollectionReference notesRef = db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .doc('Cookies')
    .collection('notes');

// Add a new note document (auto-generated ID)
await notesRef.add({
  'uuid': 'Scott',
  'content': {
    'step1': 'Try adding a pinch of sea salt for balance.',
    'step2': 'Add extra chocolate chips',
  },
  'createdAt': FieldValue.serverTimestamp(),
});

Set servertimestamp for Document Field

import {doc, addDoc, serverTimestamp} from "fusabase/oracledb";

// Base reference
const userRef = collection(db, "users");

// 1 Create a recipe with server timestamps
await addDoc( userRef , {
  name: "John",
  createdAt: serverTimestamp(),
});
import oracledb from "fusabase-ns/oracledb";

await db.collection("users")
  .add({
    name: "John",
    createdAt: oracledb.FieldValue.serverTimestamp()
}) 
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

Map<String, Object> userData = new HashMap<>();
userData.put("name", "John");
userData.put("createdAt", FieldValue.serverTimestamp());

// Add the document (auto-generated ID)
await db.collection("users").add(userData);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("users")
.addDocument(data: [
"name": "John", 
"createdAt": FieldValue.serverTimestamp()
])
// Base reference
final CollectionReference userRef = db
    .collection('users');

await userRef.add({
  "name": "John",
  "createdAt": FieldValue.serverTimestamp()
});

22.2.2 Writing Data: Updating Document Examples

Updating a Document (Field Methods)

This operation updates specific nested fields in an existing document. It fails if the document doesn’t exist.

import {doc, updateDoc} from "fusabase/oracledb";

// Reference to the existing note document
const noteRef = doc(db, "users", "Scott", "recipes", "Cookies", "notes", "note1");

// Update step2 in the content object
await updateDoc(noteRef, {
"content.step2": "Add a handful of chopped nuts instead of chocolate chips",
"content.step3":"Add some coffee as well"
});
// Reference to the existing note document
const noteRef = db.collection("users")
    .doc("Scott")
    .collection("recipes")
    .doc("Cookies")
    .collection("notes")
    .doc("note1");

// Update step2 in the content object
noteRef.update({
  "content.step2": "Add a handful of chopped nuts instead of chocolate chips",
  "content.step3": "Add some coffee as well"
})
import com.oracle.mobile.fusabase.oracledb.DocumentReference;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import java.util.HashMap;
import java.util.Map;

FusabaseOracledb db = FusabaseOracledb.getInstance();

// Reference to the existing note document
DocumentReference noteRef = db.collection("users")
.document("Scott")
.collection("recipes")
.document("Cookies")
.collection("notes")
.document("note1");

// Create the update content
Map<String, Object> update = new HashMap<>();
update.put("content.step2", "Add a handful of chopped nuts instead of chocolate chips");
update.put("content.step3", "Add some coffee as well");

// Update step2 in the content field
noteRef.update(update);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let noteRef = db
    .collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")
    .document("note1")

noteRef.updateData([
    "content.step2":
        "Add a handful of chopped nuts instead of chocolate chips",
    "content.step3": "Add some coffee as well"
])

// Reference to the existing note document
final DocumentReference noteRef = db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .doc('Cookies')
    .collection('notes')
    .doc('note1');

// Update nested fields using dot notation
await noteRef.update({
  'content.step2':
      'Add a handful of chopped nuts instead of chocolate chips',
  'content.step3': 'Add some coffee as well',
});

Update on Field with Space

import {doc, updateDoc} from "fusabase/oracledb";

// Reference to the existing note document
const noteRef = doc(db, "users", "Scott", "recipes", "Cookies", "notes", "note1");

// Update step2 in the content object
await updateDoc(noteRef, {
"content step2": "Add a handful of chopped nuts instead of chocolate chips",
"content step3":"Add some coffee as well"
});
// Reference to the existing note document
const noteRef = db.collection("users")
    .doc("Scott")
    .collection("recipes")
    .doc("Cookies")
    .collection("notes")
    .doc("note1");

// Update step2 in the content object
noteRef.update({
  "content step2": "Add a handful of chopped nuts instead of chocolate chips",
  "content step3": "Add some coffee as well"
})
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.DocumentReference;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Reference to the existing note document
DocumentReference noteRef = db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")
    .document("note1");

// Update the document
await noteRef.update("content step2", "Add a handful of chopped nuts instead of chocolate chips",
                     "content step3", "Add some coffee as well");
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let noteRef = db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")
    .document("note1")

noteRef.updateData([
    "content step2": "Add a handful of chopped nuts instead of chocolate chips",
    "content step3": "Add some coffee as well"
])
// Reference to the existing note document
final DocumentReference noteRef = db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .doc('Cookies')
    .collection('notes')
    .doc('note1');

// Update nested fields using dot notation
await noteRef.update({
  "content step2":
      'Add a handful of chopped nuts instead of chocolate chips',
  "content step3": 'Add some coffee as well',
});

Bulk Updates Given Query Condition

import {collection, updateDocs} from "fusabase/oracledb";

// Reference to the existing note document
const noteRef = collection(db, "users", "Scott", "recipes", "Cookies", "notes");

// Update step2 in the content object
await updateDocs(noteRef).update({
"content.step2": "Add a handful of chopped nuts instead of chocolate chips",
"content.step3":"Add some coffee as well"
});
db.updateDocs("users/Scott/recipes/Cookies/notes").update({
  "content.step2": "Add a handful of chopped nuts instead of chocolate chips",
  "content.step3": "Add some coffee as well"
})
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.DocumentReference;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Reference to the existing note document
DocumentReference noteRef = db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")
    .document("note1");

// Update nested fields in the content object
await noteRef.update("content.step2", "Add a handful of chopped nuts instead of chocolate chips",
                     "content.step3", "Add some coffee as well");
import FusabaseOracledb
let db = FusabaseOracledb.oracledb()

let noteRef = db.collection("users")
    .document("Scott")
    .collection("recipes")
    .document("Cookies")
    .collection("notes")
    .document("note1")

noteRef.updateData([
    FieldPath(dotPath: "content.step2"): "Add a handful of chopped nuts instead of chocolate chips",
    FieldPath(dotPath: "content.step3"): "Add some coffee as well"
])
await db.updateDocs("users/Scott/recipes/Cookies/notes").update({
  'content.step2':
      'Add a handful of chopped nuts instead of chocolate chips',
  'content.step3': 'Add some coffee as well',
});

22.3 Reading Data

Read All Documents within a Collection

This operation reads all documents within a specified collection and logs their content.

import {collection, getDocs} from "fusabase/oracledb";

const q = collection(db, "users", "Scott", "recipes");
const snapshot = await getDocs(q);
snapshot.forEach(doc => {
  console.log(doc.id, "=>", doc.data());
});
db.collection("users").doc("Scott").collection("recipes").get().then(snapshot => {
  snapshot.forEach(doc => {
    console.log(doc.id, "=>", doc.data());
  });
});
import android.util.Log;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.collection("users").document("Scott").collection("recipes")
  .get()
  .addOnSuccessListener(snapshot -> {
    for (DocumentSnapshot doc : snapshot) {
        Log.d("Oracledb", doc.getId() + " => " + doc.getData());
    }
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("users").document("Scott").collection("recipes").getDocuments { (snapshot, error) in
  snapshot?.documents.forEach { doc in
    print("\(doc.documentID) => \(doc.data())")
  }
}
final snapshot = await db.collection('users').doc('Scott').collection('recipes').get();
snapshot.docs.forEach((doc) => print("${doc.id} => ${doc.data()}"));

Read Specific Document within a Collection

This operation reads a single document within a collection using its ID and logs its contents.

import {doc, getDoc} from "fusabase/oracledb";

const docSnap = await getDoc(doc(db, "recipes", "Cookies"));
if (docSnap.exists()) {
  console.log("Recipe:", docSnap.data());
}
db.collection("recipes").doc("Cookies").get().then(doc => {
  if (doc.exists) console.log("Recipe:", doc.data());
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.collection("recipes").document("Cookies").get().addOnSuccessListener(doc -> {
    if (doc.exists()) Log.d("Oracledb", "Recipe: " + doc.getData());
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("recipes").document("Cookies").getDocument { (doc, error) in
  if let doc = doc, doc.exists {
    print("Recipe: \(doc.data())")
  }
}
final doc = await db.collection('recipes').doc('Cookies').get();
if (doc.exists) print("Recipe: ${doc.data()}");

Run a Query Using a Filter

This operation retrieves documents that match a specific field condition (For example, difficulty = "Easy").

import {query, collection, where, getDocs} from "fusabase/oracledb";

const q = query(collection(db, "recipes"), where("difficulty", "==", "Easy"));
const snapshot = await getDocs(q);
snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
db.collection("recipes").where("difficulty", "==", "Easy").get().then(snapshot => {
  snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.collection("recipes").whereEqualTo("difficulty", "Easy").get()
  .addOnSuccessListener(snapshot -> {
    for (DocumentSnapshot doc : snapshot) Log.d("Oracledb", doc.getId() + " => " + doc.getData());
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("recipes").whereField("difficulty", isEqualTo: "Easy").getDocuments { (snapshot, error) in
  snapshot?.documents.forEach { doc in
    print("\(doc.documentID) => \(doc.data())")
  }
}
final snapshot = await db.collection('recipes').where('difficulty', isEqualTo: 'Easy').get();
snapshot.docs.forEach((doc) => print("${doc.id} => ${doc.data()}"));

Order and Limit Result Set

This operation sorts documents by a field (For example, createdAt) and limits the result to 10.

import {query, collection, orderBy, limit, getDocs} from "fusabase/oracledb";

// Query: Order by 'createdAt' and limit results to 10
const q = query(
  collection(db, "recipes"),
  orderBy("createdAt"),
  limit(10)
);

// Execute the query
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  console.log(doc.id, "=>", doc.data());
});
// Query: Order by 'createdAt' and limit results to 10
const query = db.collection("recipes")
    .orderBy("createdAt")
    .limit(10);

// Execute the query
query.get().then(snapshot => {
    snapshot.forEach(doc => {
        console.log(doc.id, "=>", doc.data());
    });
});
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;
import com.oracle.mobile.fusabase.oracledb.QuerySnapshot;

FusabaseOracledb db = FusabaseOracledb.getInstance();

// Query: Order by 'createdAt' and limit results to 10
Query query = db.collection("recipes")
                .orderBy("createdAt")
                .limit(10);

query.get().addOnCompleteListener(task -> {
     if (task.isSuccessful()) {
         QuerySnapshot snapshot = task.getResult();
         for (DocumentSnapshot document : snapshot.getDocuments()) {
              System.out.println(document.getId() + " => " + document.getData());
      }
    }
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

db.collection("recipes")
    .order(by: "createdAt")  // Order by 'createdAt' field
    .limit(to: 10)           // Limit the results to 10
    .getDocuments { (snapshot, error) in
        snapshot?.documents.forEach { doc in
            print("\(doc.documentID) => \(doc.data())")
        }
    }
final snapshot = await db.collection('recipes')
    .orderBy('createdAt')  // Order by 'createdAt' field
    .limit(10)              // Limit the results to 10
    .get();

snapshot.docs.forEach((doc) => print("${doc.id} => ${doc.data()}"));

Select Specific Columns

The following example retrieves specific field rather then complete document data.

import {collection, query} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes")).column(["tags","userid"]);
const query = db.collection("users").doc("Scott").collection("recipes").column(["tags","userid"]);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").column(List.of("tags","userid"));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let query = db.collection("users").document("Scott").collection("recipes").column(["tags","userid"]);
final query = db.collection('users').doc('Scott').collection('recipes').column(["tags","userid"]);

22.3.1 Reading Data Modifiers Examples

Sort Documents Based on a Field

The following example retrieves all recipes ordered by views in descending order.

import {collection, orderBy} from "fusabase/oracledb";

const q = query(collection(db, "recipes"), orderBy("views", "desc"));
const q = db.collection("recipes").orderBy("views", "desc");
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("recipes").orderBy("views", Query.Direction.DESCENDING);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("recipes").orderBy("views", descending: true)
final q = db.collection('recipes').orderBy('views', descending: true);

Paginate Data (startAt / endAt)

startAt / endAt is used for paginating or limiting results to a starting or ending point.

The following example retrieves recipes starting from a specific views value.

import {collection, query, orderBy, startAt, endAt} from "fusabase/oracledb";

const q = query(
  collection(db,"users","Scott","recipes"),
  orderBy("createdAt"),
  startAt(new Date("2025-01-01")),
  endAt(new Date("2025-12-31"))
);
const q = db.collection("users").doc("Scott").collection("recipes")
  .orderBy("createdAt")
  .startAt(new Date("2025-01-01"))
  .endAt(new Date("2025-12-31"));
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").doc("Scott").collection("recipes")
    .orderBy("createdAt")
    .startAt(Timestamp.ofTimeSecondsAndNanos(1735689600L, 0))
    .endAt(Timestamp.ofTimeSecondsAndNanos(1767225600L, 0));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let q = db.collection("users").document("Scott").collection("recipes")
    .order(by: "createdAt")
    .start(at: [Timestamp(date: DateComponents(calendar: .current, year: 2025, month: 1, day: 1).date!)])
    .end(at: [Timestamp(date: DateComponents(calendar: .current, year: 2025, month: 12, day: 31).date!)])
final q = db.collection('users').doc('Scott').collection('recipes')
    .orderBy('createdAt')
    .startAt([DateTime(2025, 1, 1)])
    .endAt([DateTime(2025, 12, 31)]);

Limitations

  • Query using null value
  • Scope of in and not in operator
  • Scope of array-contains-any

22.3.2 Reading Data Filter Documents Examples

Filter Document with Equality (= =)

Using the equality operator finds documents where a field is equal to a given value. The following example retrieves all recipes where category is "Dessert."

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("category", "==", "Dessert"));
db.collection("users").doc("Scott").collection("recipes").where("category", "==", "Dessert");
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereEqualTo("category", "Dessert");
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("category", isEqualTo: "Dessert")
final q = db.collection('users').doc('Scott').collection('recipes').where('category', isEqualTo: 'Dessert');

Filter Document with Equality (!=)

Using the inequality operator finds documents where a field is not equal to a given value. The following example retrieves all recipes where category is not "Dessert."

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("category", "!=", "Dessert"));
db.collection("users").doc("Scott").collection("recipes").where("category", "!=", "Dessert");
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereNotEqualTo("category", "Dessert");
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("category", isNotEqualTo: "Dessert")
final q = db.collection('users').doc('Scott').collection('recipes').where('category', isNotEqualTo: 'Dessert');

Filter Document with Greater Than (>)

Using the greater than operator finds documents where a field is greater than a given value. The following example retrieves all recipes where views are greater than 1000.

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("views", ">", 1000));
db.collection("users").doc("Scott").collection("recipes").where("views", ">", 1000);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereGreaterThan("views", 1000);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

// Retrieve all recipes where `views` > 1000
let q = db
  .collection("users")
  .document("Scott")
  .collection("recipes")
  .whereField("views", isGreaterThan: 1000)
// Retrieve all recipes where `views` > 1000
final q = db
    .collection('users')
    .doc('Scott')
    .collection('recipes')
    .where('views', isGreaterThan: 1000);

Filter Document with Greater Than (>=)

Using the greater than or equal to operator finds documents where a field is greater than or equal to a given value. The following example retrieves all recipes where views are greater than or equal to 1000.

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("views", ">=", 1000));
db.collection("users").doc("Scott").collection("recipes").where("views", ">=", 1000);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereGreaterThanOrEqualTo("views", 1000);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("views", isGreaterThanOrEqualTo: 1000)
final q = db.collection('users').doc('Scott').collection('recipes').where('views', isGreaterThanOrEqualTo: 1000);

Filter Document with Less Than (<)

Using the less than operator finds documents where a field is less than a given value. The following example retrieves all recipes where views are less than 1000.

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("views", "<", 1000));
db.collection("users").doc("Scott").collection("recipes").where("views", "<", 1000);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereLessThan("views", 1000);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("views", isLessThan: 1000)
final q = db.collection('users').doc('Scott').collection('recipes').where('views', isLessThan: 1000);

Filter Document with Less Than or Equal (<=)

Using the less than or equal to operator finds documents where a field is less than or equal to a given value. The following example retrieves all recipes where views are less than or equal to 1000.

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("views", "<=", 1000));
db.collection("users").doc("Scott").collection("recipes").where("views", "<=", 1000);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereLessThanOrEqualTo("views", 1000);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("views", isLessThanOrEqualTo: 1000)
final q = db.collection('users').doc('Scott').collection('recipes').where('views', isLessThanOrEqualTo: 1000);

Filter Document with array-contains

Using array-contains finds documents where an array field contains a given value. The following example retrieves all recipes that include "sweet" in the tags array.

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("tags", "array-contains", "sweet"));
db.collection("users").doc("Scott").collection("recipes").where("tags", "array-contains", "sweet");
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereArrayContains("tags", "sweet");
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("tags", arrayContains: "sweet")
final q = db.collection('users').doc('Scott').collection('recipes').where('tags', arrayContains: 'sweet');

Filter Document with array-contains-any

Using array-contains-any finds documents where an array field contains any of the given value. The following example retrieves recipes where tags array contains either "sweet" or "baking".

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("tags", "array-contains-any", ["sweet", "baking"]));
db.collection("users").doc("Scott").collection("recipes").where("tags", "array-contains-any", ["sweet", "baking"]);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereArrayContainsAny("tags", Arrays.asList("sweet", "baking"));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("tags", arrayContainsAny: ["sweet", "baking"])
final q = db.collection('users').doc('Scott').collection('recipes').where('tags', arrayContainsAny: ['sweet', 'baking']);

Filter Document with in

Using in finds documents where a field is equal to one of the provided values. The following example retrieves recipes where category is either "Dessert" or "Snack".

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("category", "in", ["Dessert", "Snack"]));
db.collection("users").doc("Scott").collection("recipes").where("category", "in", ["Dessert", "Snack"]);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereIn("category", Arrays.asList("Dessert", "Snack"));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("category", in: ["Dessert", "Snack"])
final q = db.collection('users').doc('Scott').collection('recipes').where('category', whereIn: ['Dessert', 'Snack']);

Filter Document with not-in

Using not-in finds documents where a field is not equal to any of the provided values. The following example retrieves recipes where category is neither "Dessert" nor "Snack".

import {collection, query, where} from "fusabase/oracledb";

const q = query(collection(db, "users", "Scott", "recipes"), where("category", "not-in", ["Dessert", "Snack"]));
db.collection("users").doc("Scott").collection("recipes").where("category", "not-in", ["Dessert", "Snack"]);
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;

FusabaseOracledb db = FusabaseOracledb.getInstance();
Query q = db.collection("users").document("Scott").collection("recipes").whereNotIn("category", Arrays.asList("Dessert", "Snack"));
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("category", notIn: ["Dessert", "Snack"])
final q = db.collection('users').doc('Scott').collection('recipes').where('category', whereNotIn: ['Dessert', 'Snack']);

22.4 Transaction and Batch Writes Examples

These examples show how to perform atomic operations using transactions and batch writes.

Transaction (Using runTransaction)

The following example atomically reads the recipe document, then in the same transaction updates the recipe’s view count and timestamps, updates the user’s last-activity timestamp, and creates a new auto-ID note document.

import {doc, collection, runTransaction, serverTimestamp} from "fusabase/oracledb";

const userRef = doc(db, "users", "Scott");
const recipeRef = doc(db, "users", "Scott", "recipes", "Cookies");
const notesColRef = collection(recipeRef, "notes");

await runTransaction(db, async (transaction) => {
  // 1 Read
  const recipeSnap = await transaction.get(recipeRef);
  if (!recipeSnap.exists()) {
    throw "Recipe does not exist";
  }

  const views = recipeSnap.data().views || 0;

  // 2 Multiple Updates
  transaction.update(recipeRef, {
    views: views + 1,
    updatedAt: serverTimestamp(),
  });

  transaction.update(userRef, {
    lastActivity: serverTimestamp(),
  });

  // 3 Add a new document (auto-ID)
  const newNoteRef = doc(notesColRef);  // Auto-generated ID
  transaction.set(newNoteRef, {
    message: "Tried adding nuts — worked great!",
    createdAt: serverTimestamp(),
  });
});
const userRef = db.collection("users").doc("Scott");
const recipeRef = userRef.collection("recipes").doc("Cookies");
const notesColRef = recipeRef.collection("notes");

await db.runTransaction(async (tx) => {
  // 1 Read
  const recipeSnap = await tx.get(recipeRef);
  if (!recipeSnap.exists) {
    throw "Recipe does not exist";
  }

  const views = recipeSnap.data().views;

  // 2 Multiple updates
  tx.update(recipeRef, {
    views: views + 1,
    updatedAt: fusabase.oracledb.FieldValue.serverTimestamp()
  });

  tx.update(userRef, {
    lastActivity: fusabase.oracledb.FieldValue.serverTimestamp()
  });

  // 3 Add new document (auto-ID like addDoc)
  const newNoteRef = notesColRef.doc(); // auto-generated ID
  tx.set(newNoteRef, {
    message: "Tried adding nuts — worked great!",
    createdAt: fusabase.oracledb.FieldValue.serverTimestamp()
  });
});
import com.oracle.mobile.fusabase.oracledb.CollectionReference;
import com.oracle.mobile.fusabase.oracledb.DocumentReference;
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;
import com.oracle.mobile.fusabase.oracledb.FieldValue;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;

FusabaseOracledb db = FusabaseOracledb.getInstance();
DocumentReference userRef = db.collection("users").document("Scott");
DocumentReference recipeRef = userRef.collection("recipes").document("Cookies");
CollectionReference notesColRef = recipeRef.collection("notes");

db.runTransaction(transaction -> {
	// 1 Read
    DocumentSnapshot recipeSnap = transaction.get(recipeRef).get();
    if (!recipeSnap.exists()) {
        throw new RuntimeException("Recipe does not exist");
     }

     Long views = recipeSnap.contains("views")
                ? recipeSnap.getLong("views")
                : 0L;

        // 2 Multiple updates
        transaction.update(recipeRef,
                "views", views + 1,
                "updatedAt", FieldValue.serverTimestamp()
        );

        transaction.update(userRef,
                "lastActivity", FieldValue.serverTimestamp()
        );

        // 3 Add document (auto-ID)
        DocumentReference newNoteRef = notesColRef.document(); // auto ID
        transaction.set(newNoteRef, Map.of(
                "message", "Tried adding nuts — worked great!",
                "createdAt", FieldValue.serverTimestamp()
        ));

        return null;
    });

import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let userRef = db.collection("users").document("Scott")
let recipeRef = db.collection("users").document("Scott").collection("recipes").document("Cookies")
let notesColRef = recipeRef.collection("notes")

db.runTransaction({ (transaction, errorPointer) -> Any? in
    // 1 Read
    let recipeSnap = try transaction.getDocument(recipeRef)
    if !recipeSnap.exists {
        throw NSError(domain: "Recipe does not exist", code: 0, userInfo: nil)
    }

    let views = recipeSnap.data()?["views"] as? Int ?? 0

    // 2 Multiple Updates
    transaction.updateData([
        "views": views + 1,
        "updatedAt": FieldValue.serverTimestamp()
    ], forDocument: recipeRef)

    transaction.updateData([
        "lastActivity": FieldValue.serverTimestamp()
    ], forDocument: userRef)

    // 3 Add a new document (auto-ID)
    let newNoteRef = notesColRef.document() // auto-generated ID
    transaction.setData([
        "message": "Tried adding nuts — worked great!",
        "createdAt": FieldValue.serverTimestamp()
    ], forDocument: newNoteRef)

    return nil
}, completion: { (result, error) in
    if let error = error {
        print("Transaction failed: \(error.localizedDescription)")
    } else {
        print("Transaction successfully committed!")
    }
})
final userRef = db.collection('users').doc('Scott');
final recipeRef = db.collection('users').doc('Scott').collection('recipes').doc('Cookies');
final notesColRef = recipeRef.collection('notes');

await db.runTransaction((transaction) async {
  // 1 Read
  final recipeSnap = await transaction.get(recipeRef);
  if (!recipeSnap.exists) {
    throw Exception("Recipe does not exist");
  }

  final views = recipeSnap.data()?['views'] ?? 0;

  // 2 Multiple Updates
  transaction.update(recipeRef, {
    'views': views + 1,
    'updatedAt': FieldValue.serverTimestamp(),
  });

  transaction.update(userRef, {
    'lastActivity': FieldValue.serverTimestamp(),
  });

  // 3 Add a new document (auto-ID)
  final newNoteRef = notesColRef.doc(); // Auto-generated ID
  transaction.set(newNoteRef, {
    'message': "Tried adding nuts — worked great!",
    'createdAt': FieldValue.serverTimestamp(),
  });
});

22.5 Advanced Features

This section provides SDK examples for the following advanced features:

  • Join Collection
  • Collection Group
  • Aggregate Queries

22.5.1 Join Collection Examples

Query Join Collection

The following example represents a query for all of recipes excluding those categorized as Dessert.

import {query, collection, where, getDocs} from "fusabase/oracledb";

const q = query(collection(db, ""), join("<view name>"));
const snapshot = await getDocs(q);
snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
db.join("<view_name>").get().then(snapshot => {
  snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
});
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.join("<view_name>").whereEqualTo("dept", "Engineering").get()
  .addOnSuccessListener(snapshot -> {
    for (DocumentSnapshot doc : snapshot) Log.d("Oracledb", doc.getId() + " => " + doc.getData());
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)
let q = db.collection("users").document("Scott").collection("recipes").whereField("category", isNotEqualTo: "Dessert")
final q = db.collection('users').doc('Scott').collection('recipes').where('category', isNotEqualTo: 'Dessert');

22.5.2 Collection Group Examples

Query Collection Group using Condition

The following example runs a collection-group query across all recipes subcollections to fetch documents where difficulty is "Easy" and logs each document’s ID and data.

import {query, collectionGroup, where, getDocs} from "fusabase/oracledb";

const q = query(collectionGroup(db, "recipes"), where("difficulty", "==", "Easy"));
const snapshot = await getDocs(q);
snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
db.collectionGroup("recipes")
  .where("difficulty", "==", "Easy")
  .get()
  .then(snapshot => snapshot.forEach(doc => console.log(doc.id, "=>", doc.data())));
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import android.util.Log;

FusabaseOracledb db = FusabaseOracledb.getInstance();
db.collectionGroup("recipes")
  .whereEqualTo("difficulty", "Easy")
  .get()
  .addOnSuccessListener(snapshot -> {
    for (DocumentSnapshot doc : snapshot)
        Log.d("Oracledb", doc.getId() + " => " + doc.getData());
});
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()

let q = db.collectionGroup("recipes").whereField("difficulty", isEqualTo: "Easy")

let snapshot = try await q.getDocuments()
for doc in snapshot.documents {
    print("\(doc.documentID) => \(doc.data())")
}
final q = db
    .collectionGroup('recipes')
    .where('difficulty', isEqualTo: 'Easy');

final snapshot = await q.get();
for (final doc in snapshot.docs) {
  print('${doc.id} => ${doc.data()}');
}

Query Collection Group for a Specific Document ID

The following example runs a collection-group query across all recipes subcollections to find documents where OID equals "ChocolateShake", fetches the matching documents, and logs each document’s ID and data.

import {query, collectionGroup, where, getDocs} from "fusabase/oracledb";

const q = query(collectionGroup(db, "recipes"), where("OID", "==", "ChocolateShake"));
const snapshot = await getDocs(q);
snapshot.forEach(doc => console.log(doc.id, "=>", doc.data()));
db.collectionGroup("recipes")
  .where("OID", "==", "ChocolateShake")
  .get()
  .then(snapshot => snapshot.forEach(doc => console.log(doc.id, "=>", doc.data())));
import com.oracle.mobile.fusabase.oracledb.DocumentSnapshot;
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import android.util.Log;

FusabaseOracledb db = FusabaseOracledb.getInstance();

db.collectionGroup("recipes")
  .whereEqualTo("OID", "ChocolateShake")
  .get()
  .addOnSuccessListener(snapshot -> {
    for (DocumentSnapshot doc : snapshot)
        Log.d("Oracledb", doc.getId() + " => " + doc.getData());
});
import FusabaseOracledb

// let db = FusabaseOracledb.oracledb()
let db = FusabaseOracledb.oracledb(app: FusabaseApp.app()!)

let q = db.collectionGroup("recipes").whereField("OID", isEqualTo: "ChocolateShake")

let snapshot = try await q.getDocuments()
for doc in snapshot.documents {
    print("\(doc.documentID) => \(doc.data())")
}
final q = db
    .collectionGroup('recipes')
    .where('OID', isEqualTo: 'ChocolateShake');

final snapshot = await q.get();
for (final doc in snapshot.docs) {
  print('${doc.id} => ${doc.data()}');
}

22.5.3 Aggregate Queries Example

Count

The following example retrieves the server-side count of matching documents, and logs the count.

import { collection, query, where, getCountFromServer } from "fusabase/oracledb";

const q = query(
  collection(db, "users"),
  where("active", "==", true)
);

const snapshot = await getCountFromServer(q);
console.log("Count:", snapshot.data().count);
const query = db.collection("users").where("active", "==", true);

query.count().get().then(snapshot => {
  console.log("Count:", snapshot.data().count);
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.Query;
import com.oracle.mobile.fusabase.oracledb.AggregateQuery;
import com.oracle.mobile.fusabase.oracledb.AggregateQuerySnapshot;
import com.oracle.mobile.fusabase.oracledb.AggregateField;
import android.util.Log;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Create query
Query q = db.collection("users").whereEqualTo("active", true);

// Get count from server
AggregateQuery countQuery = q.aggregate(AggregateField.count());
AggregateQuerySnapshot snapshot = await countQuery.get();
long count = snapshot.getCount();
Log.i("Oracledb","Count: " + count);
import FusabaseOracledb
let db = FusabaseOracledb.oracledb()
    
let q = db.collection("users")
           .whereField("active", isEqualTo: true)
    
let snapshot = try await q.count.getAggregate(source: .server)
print("Count:", snapshot.count.intValue)
final query = db
  .collection("users")
  .where("active", isEqualTo: true);

final snapshot = await query.count().get();
print("Count: ${snapshot.count}");

Sum

The following example runs an aggregation over the orders collection to sum the price field (as totalRevenue) and logs the resulting total.

import { collection, getAggregateFromServer, sum } from "fusabase/oracledb";

const q = collection(db, "orders");

const snapshot = await getAggregateFromServer(q, {
  totalRevenue: sum("price")
});

console.log("Sum:", snapshot.data().totalRevenue);
import oracledb from "fusabase-ns/oracledb";

const query = db.collection("orders");

query.aggregate({
  totalRevenue: oracledb.AggregateField.sum("price")
}).get().then(snapshot => {
  console.log("Sum:", snapshot.data().totalRevenue);
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.CollectionReference;
import com.oracle.mobile.fusabase.oracledb.AggregateQuery;
import com.oracle.mobile.fusabase.oracledb.AggregateQuerySnapshot;
import com.oracle.mobile.fusabase.oracledb.AggregateField;
import android.util.Log;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Get collection reference
CollectionReference q = db.collection("orders");

// Create aggregate query for sum of price field
AggregateQuery sumQuery = q.aggregate(AggregateField.sum("totalRevenue", "price"));
AggregateQuerySnapshot snapshot = await sumQuery.get();
double totalRevenue = snapshot.getDouble("totalRevenue");
Log.i("Oracledb","Sum: " + totalRevenue);
import FusabaseOracledb
let db = FusabaseOracledb.oracledb()
    
let q = db.collection("orders")
    
// Create aggregate field for summing the price
let totalRevenueField = AggregateField.sum("price")
    
// Create aggregate query
let aggregateQuery = q.aggregate([totalRevenueField])
    
// Execute the aggregate query
let snapshot = try await aggregateQuery.getAggregate(source: .server)
    
// Get the result
let totalRevenue = snapshot.get(totalRevenueField)
print("Sum:", totalRevenue)
final snapshot = await db
  .collection("orders")
  .aggregate(sum("price"))
  .get();

print("Sum: ${snapshot.get("sum_price")}");

Average

The following example computes the server-side average of the rating field across all documents in the reviews collection and logs the result.

import { average } from "fusabase/oracledb";

const snapshot = await getAggregateFromServer(
  collection(db, "reviews"),
  { avgRating: average("rating") }
);

console.log("Average:", snapshot.data().avgRating);
import oracledb from "fusabase-ns/oracledb";

db.collection("reviews").aggregate({
  avgRating: oracledb.AggregateField.average("rating")
}).get().then(snapshot => {
  console.log("Average:", snapshot.data().avgRating);
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.AggregateQuery;
import com.oracle.mobile.fusabase.oracledb.AggregateQuerySnapshot;
import com.oracle.mobile.fusabase.oracledb.AggregateField;
import android.util.Log;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Create aggregate query for average rating
AggregateQuery avgQuery = db.collection("reviews").aggregate(AggregateField.average("avg_rating", "rating"));
AggregateQuerySnapshot snapshot = await avgQuery.get();
double average = snapshot.getDouble("avg_rating");
Log.i("Oracledb","Average: " + average);
import FusabaseOracledblet db = FusabaseOracledb.oracledb()

let collection = db.collection("reviews")

// Create aggregate field for averaging the rating
let avgRatingField = AggregateField.average("rating")

// Create and execute aggregate query
let aggregateQuery = collection.aggregate([avgRatingField])
let snapshot = try await aggregateQuery.getAggregate(source: .server)

// Get the result
let avgRating = snapshot.get(avgRatingField)
print("Average:", avgRating)
final snapshot = await db
  .collection("reviews")
  .aggregate(average("rating"))
  .get();

print("Average: ${snapshot.get("avg_rating")}");

Combination of Count, Sum, and Average

The following example runs aggregation on the orders collection to compute the total order count, sum of price (total revenue), and average price, then prints the results.

import {
  collection,
  getAggregateFromServer,
  count,
  sum,
  average
} from "fusabase/oracledb";

const ordersRef = collection(db, "orders");

const snapshot = await getAggregateFromServer(ordersRef, {
  totalOrders: count(),
  totalRevenue: sum("price"),
  avgOrderValue: average("price"),
});

console.log(snapshot.data());
import oracledb from "fusabase-ns/oracledb";
db.collection("orders").aggregate({
  totalOrders: oracledb.AggregateField.count(),
  totalRevenue: oracledb.AggregateField.sum("price"),
  avgOrderValue: oracledb.AggregateField.average("price")
}).get().then(snapshot => {
  console.log(snapshot.data());
});
import com.oracle.mobile.fusabase.oracledb.FusabaseOracledb;
import com.oracle.mobile.fusabase.oracledb.AggregateQuery;
import com.oracle.mobile.fusabase.oracledb.AggregateQuerySnapshot;
import com.oracle.mobile.fusabase.oracledb.AggregateField;
import android.util.Log;

// Get database instance
FusabaseOracledb db = FusabaseOracledb.getInstance();

// Create aggregate query with multiple fields
AggregateQuery multiAggQuery = db.collection("orders").aggregate(
    AggregateField.count("totalOrders"),
    AggregateField.sum("totalRevenue", "price"),
    AggregateField.average("avgOrderValue", "price")
);

AggregateQuerySnapshot snapshot = await multiAggQuery.get();

// Access the results
long totalOrders = snapshot.getCount("totalOrders");
double totalRevenue = snapshot.getDouble("totalRevenue");
double avgOrderValue = snapshot.getDouble("avgOrderValue");

Log.i("Oracledb","Total Orders: " + totalOrders);
Log.i("Oracledb","Total Revenue: " + totalRevenue);
Log.i("Oracledb","Average Order Value: " + avgOrderValue);
import FusabaseOracledb

let db = FusabaseOracledb.oracledb()
    
// Create aggregate fields
let totalOrders = AggregateField.count()
let totalRevenue = AggregateField.sum("price")
let avgOrderValue = AggregateField.average("price")
    
// Create aggregate query with multiple fields
let aggregateQuery = db.collection("orders").aggregate([totalOrders, totalRevenue, avgOrderValue])
    
// Execute the aggregate query
let snapshot = try await aggregateQuery.getAggregate(source: .server)
    
// Collect results (equivalent to snapshot.data() in JavaScript)
let data: [String: Any] = [
    "totalOrders": snapshot.get(totalOrders),
    "totalRevenue": snapshot.get(totalRevenue),
    "avgOrderValue": snapshot.get(avgOrderValue)
]
    
print(data)
final ordersRef = db.collection('orders');

final snapshot = await ordersRef.aggregate({
  'totalOrders': AggregateField.count(),
  'totalRevenue': AggregateField.sum('price'),
  'avgOrderValue': AggregateField.average('price'),
}).get();

print(snapshot.data());