Document Operations

Oracle Backend with Firebase APIs provides a unified document-centric interface for interacting with both relational and document-based data. This section introduces the conceptual foundation for document operations, focusing on how developers can model, write, and read data using Oracle Backend with Firebase APIs.

Document operations in Oracle Backend with Firebase APIs refer to the lifecycle actions developers perform on JSON-based documents stored within collections. These operations include creating, updating, reading, and deleting documents, along with applying field-level modifiers and managing metadata. Oracle Backend with Firebase APIs supports both document and relational models, and these operations apply primarily to the document model.

Information in this section is intended to help developers understand the underlying principles before diving into SDK-specific implementations.

For offline behavior in JavaScript applications, see Access Data Offline in JavaScript Applications.

Prerequisites

Before performing any document read or write operations, ensure the following:

Write Operations

Write operations in Oracle Backend with Firebase APIs allow developers to create, update, and delete documents within collections. These operations are designed to support both full document replacements and granular field-level updates.

Supported Document Operations

Developers can perform the following operations on documents. Each of these operations can be invoked using REST or SDK interfaces.

Table 17-1 Write Operations

Operation Method Description
Set a Document setDoc(path, data, options) Create or overwrite a document at the specified path; can also merge document data. If the collection does not exist, it is created automatically.
Add a Document addDoc(path, data) Inserts a new JSON document into a specified collection or sub-collection with an auto-generated unique identifier (OID).
Update Document updateDoc() Updates specific fields in an existing document using its OID.
Delete Document deleteDoc() Removes a document from the collection.

Note: For multi-step writes, use batch writes (all-or-nothing) or transactions (read + write atomically).

SDK Usage

Set a Document

The setDoc() operation is used to create or overwrite a document at a specified path. Unlike addDoc(), which generates an auto-ID, setDoc() requires you to specify the document path within a collection and provide the document data.

If the document being created already exists, it can be overwritten entirely or updated partially using one of these merge options:

If the document does not exist, it will be created at the given path. If the collection does not already exist, this operation implicitly creates the collection. The field methods listed in Field-Level Semantics and Data Types can be applied. Relational Model updates operate on duality views created from relational tables.

Merging allows developers to update specific fields within a document without replacing the entire content. This is useful for incremental updates, such as modifying a title or adding new tags.

By default, when you call setDoc() without specifying merge options, the entire document is overwritten with the new data you provide.

Setting a Document Using the Console

  1. Navigate to the Database section in the Console.

  2. Select the Collection where you want the document.

  3. Choose Add Document but manually specify the document ID (For example, Scott, Cookies).

    Note: When you set a document you control the document ID. The Console requires you to type it in.

  4. Enter field values in the document editor.

  5. Optionally, enable merge mode (if supported in the Console UI) to update only specific fields.

  6. Save, and the document is created or overwritten at that exact path.

Example: Set a Document with Merge Options

Merge and MergeFields options are supported in Oracle Backend with Firebase APIs to allow fine-grained control over document updates.

Overwrite Document (merge = false)

Setting a document with merge = false (which is the default) replaces the entire document with the provided data. Use this when you want to ensure the document is fully reset or when you are not sure if it exists.

{
  "displayName": "Scott",
  "photoURL": null
}

Merge Document (merge = true)

This option tells the system to merge the incoming fields with the existing document rather than replacing the entire document. Therefore, this operation adds new fields or updates specified existing fields. Other fields remain untouched. This option is useful for incremental updates without overwriting the entire document.

The following is an example input:

{
  "title": "Rich Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cup chocolate chips"
}

The following is the resulting document, after it is merged into the existing document:

{
  "uuid": "Scott",
  "title": "Rich Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cup chocolate chips",
  "avgRating": 0,
  "tags": ["sweet", "baking"]
}

Example 17-1 merge: true

The following updates only views and notes fields, leaving other fields untouched.

{
  "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 },
  "notes": "deleteField"
}

The following is the resulting document:

{
  "title": "Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cups chocolate chips",
  "tags": ["sweet", "baking", "dessert"],
  "createdAt": "2025-12-22T12:53:00Z",
  "updatedAt": "2025-12-22T12:53:00Z",
  "views": 101,   // incremented from 100
  // "notes" field removed
}

mergeFields: [“field1”, “field2”]

This option is more selective because it allows you to merge only specific fields from the payload, ignoring others even if they are present. This is different from a full merge (merge = true), which merges all provided fields. With merge fields, you can explicitly list which fields should be merged.

Example 17-2 mergeFields: [“field1”, “field2”]

Only field1 and field2 are updated. field3 is ignored even though it is present in the payload.

Suppose that the target document path is /users/Scott/recipes/Cookies and the content to be updated is:

{
  "title": "Rich Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cup chocolate chips",
  "avgRating": 5
}

Suppose that the following merge fields option are used:

{
  "mergeFields": ["title", "ingredients"]
}

After applying the merge with mergeFields, the resulting document is as follows:

{
  "uuid": "Scott",
  "title": "Rich Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cup chocolate chips",
  "avgRating": 0,              // unchanged because not listed in mergeFields
  "tags": ["sweet", "baking"]  // untouched
}

Add a Document

This operation adds a new document to a collection or a relational model with an auto-generated identifier. It is typically used when the document ID is not predetermined and allows for rapid creation of new entries. This operation is distinct from setDoc() (which overwrites or merges existing documents) because addDoc() always generates a new document with a system‐assigned identifier.

The add data operation is supported in both collection model (JSON) and relational model (duality view). When invoked:

The modifier serverTimestamp stores the current server time, which is useful for createdAt fields.

Adding Data Using the Console

Developers can add data directly through the Console without writing SDK code.

  1. Navigate to the Database section of your project.

  2. Select the mapped relational table or document collection.

    For relational tables, ensure relational tables are mapped in the Console. Oracle Backend with Firebase APIs automatically creates duality views for each mapping.

    For document collection, select the target collection path: users/{userid}/recipes/{recipeId}/notes.

  3. Click Add Document.

  4. Enter the JSON structure above into the document editor.

  5. Save the document.

    • The system generates a unique ID for the new note.

    • Metadata (OID, parent_oid, _metadata) is automatically generated.

    • The createdAt field is automatically populated with the server time.

Example: Adding Data in Document Model

When adding a new document into a subcollection (for example, notes under a recipe), the structure of the data can be represented as follows:

{
  "uuid": "Scott",
  "content": {
    "step1": "Try adding a pinch of sea salt for balance.",
    "step2": "Add extra chocolate chips"
  },
  "createdAt": "serverTimestamp"
}

Adding Data in Relational Model

When using Oracle Backend with Firebase APIs with relational tables, adding data creates a hybrid collection that extends the relational schema. Each relational table is converted into a duality view with metadata fields such as oid and parent_oid.

A new document added to such a hybrid collection can be represented in JSON as follows:

{
  "osons": {
    "name": "Scott",
    "age": 30,
    "about": "Application developer working with Oracle Backend with Firebase APIs",
    "OID": "FB03C10200",
    "_id": 1,
    "parent_oid": "_docId",
    "_metadata": {
      "etag": "943EEC508908213D2D00FF375854BB48",
      "asof": "00000000000001234"
    }
  }
}

Update a Document

Updating a document allows you to change only specific fields in an existing document. Unlike setDoc(), which overwrites or merges entire documents, the update operation is designed for partial modifications.

If the document does not already exist, the update operation fails. This ensures that updates are only applied to valid, existing records. Also, the update operation supports bulk updates using the filter clause, which iterate through each document that is part of the clause and updates the documents. In case of security issue with any of the document, the complete operation is rolled back.

When updating, the field methods listed in Field-Level Semantics and Data Types can be applied. Relational Model updates operate on duality views created from relational tables.

Updating a Document Using the Console

  1. Navigate to the Database section in the Console.

  2. Select the collection or relational duality view where you want to update the document.

    Example path: /users/{userid}/recipes/{recipeid}/notes/{noteid}

  3. Click the document ID to open its details.

  4. Enter field values in the document editor.

  5. Complete the following tasks:

    • In the document editor, specify the fields to be updated.

    • Use dot notation for nested fields (for example, content.step2).

    • Example update content:

      {
        "content.step2": "Add a handful of chopped nuts instead of chocolate chips",
        "content.step3": "Add some coffee as well"
      }
  6. Choose Update Document from the available actions and confirm the operation.

Example: Updating data in Document Model

In the earlier example for adding data, suppose you want to:

The update request would look like this:

{
  "content.step2": "Add a handful of chopped nuts instead of chocolate chips",
  "content.step3": "Add some coffee as well"
}

After the update, the document will contain:

{
  "uuid": "Scott",
  "content": {
    "step1": "Try adding a pinch of sea salt for balance.",
    "step2": "Add a handful of chopped nuts instead of chocolate chips",
    "step3": "Add some coffee as well"
  },
  "createdAt": "serverTimestamp"
}

Example: Updating Data in Relational Model

In the earlier example for adding data, suppose you want to:

The update request would look like:

{
  "age": 31,
  "about": "Updated profile information"
}

After the update, the duality view reflects the following:

{
  "osons": {
    "name": "Scott",
    "age": 31,
    "about": "Updated profile information",
    "OID": "FB03C10200",
    "_id": 1,
    "parent_oid": "_docId",
    "_metadata": {
      "etag": "NEW_ETAG_VALUE",
      "asof": "NEW_ASOF_VALUE"
    }
  }
}

Metadata (etag, asof) is automatically updated to reflect the new version.

Delete a Document

The delete operation removes an entire document from a collection or relational duality view.

Important:

Caution: This operation is irreversible and should be used with caution, especially in production environments.

Deleting Data Using the Console

  1. Navigate to the Database section of your project.

  2. Use the project hierarchy to browse to the correct collection or relational duality view.

    For document collection, select the target collection path: /users/{userid}/recipes/{recipeid}/notes/{noteid}.

  3. Search or filter to find the document you want to delete and click the document ID to open its details.

  4. Click Delete Document.

  5. Confirm the deletion when prompted.

Example: Deleting a Document

Suppose that the target document path: /users/Scott/recipes/Cookies/notes/note1 and the delete request is:

{
  "operation": "deleteDoc",
  "path": "/users/Scott/recipes/Cookies/notes/note1"
}

The document note1 is removed from the notes subcollection. Any subcollections under note1 (For example, attachments, comments) remain unless explicitly deleted.

Field-Level Semantics and Data Types

Oracle Backend with Firebase APIs supports advanced field-level operations using built-in field modifiers that enhance document write operations. These modifiers are applied to manage dynamic data during document creation or update (set and update operations):

These operations allow developers to perform complex updates without needing to read and rewrite entire documents.

serverTimestamp

The following is an example of an input:

{
  "createdAt": "serverTimestamp",
  "updatedAt": "serverTimestamp"
}

The following is the example of the resulting document:

{
  "createdAt": "2025-12-22T15:37:00Z",
  "updatedAt": "2025-12-22T15:37:00Z"
}

increment

The following is an example of an input:

{
  "views": { "increment": 1 }
}

The following is the example of the resulting document (if previous value was 100):

{
  "views": 101
}

arrayUnion

The following is an example of an input:

{
  "tags": { "arrayUnion": ["dessert"] }
}

The following is the example of the resulting document (if previous tags were ["sweet", "baking"]):

{
  "tags": ["sweet", "baking", "dessert"]
}

arrayRemove

The following is an example of an input:

{
  "tags": { "arrayRemove": ["baking"] }
}

The following is the example of the resulting document (if previous tags were ["sweet", "baking", "dessert"]):

{
  "tags": ["sweet", "dessert"]
}

deleteField

The following is an example of an input:

{
  "notes": "deleteField"
}

The following is the example of the resulting document:

{
  // "notes" field removed
}

Combined Example

Developers can combine multiple field methods in a single operation:

The following is an example of an input:

{
  "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 },
  "notes": "deleteField"
}

The following is the example of the resulting document:

{
  "title": "Chocolate Chip Cookies",
  "ingredients": "2 cups flour,1 cup sugar,2 cups chocolate chips",
  "tags": ["sweet", "baking", "dessert"],
  "createdAt": "2025-12-22T15:37:00Z",
  "updatedAt": "2025-12-22T15:37:00Z",
  "views": 101
  // "notes" field removed
}

Supported Data Types

The allowed data types for write operations include:

Security Rule Enforcement

Before running any document operation, Oracle Backend with Firebase APIs system validates the request against CEL-based security rules for database documents. These rules are compiled into SQL expressions and enforced at runtime to determine whether a user is authorized to perform a given operation on a document or collection.

The following must be noted about security rule enforcement:

Each rule entry includes:

Field Description
collection_name Target collection or sub-collection
operation Type of operation (For example, addDoc, updateDoc)
rule_expr CEL expression that defines access logic
enabled Boolean flag to activate or deactivate the rule

Supported Operations

Rules can be defined for the following operations:

Each rule is evaluated before the operation is executed. If the rule fails, the operation is blocked and an error is returned.

Example 17-3 Rule

To restrict updates to documents where the user is the creator:

rule_expr = "request.auth.uid == resource.data.created_by"

This ensures that only the original creator can update the document.

Variables for CEL Rules

Variable Description
request.auth Authenticated user info (For example, uid, email)
request.time Timestamp of the request
resource.data Existing document data
request.data Incoming payload data

Read Operations

Read operations in Oracle Backend with Firebase APIs allow developers to retrieve structured data in documents from both collection-based and relational models. These operations are designed to be shallow by default, meaning that subcollections are not automatically fetched unless explicitly requested.

Read operations have the following characteristics:

Oracle Backend with Firebase APIs supports the following two primary models for document storage and retrieval. Each model supports full document retrieval, filtered queries, and advanced operations like joins and collection groups.

Example 17-4 Collection Model Read Output

{
  "ret": [{
    "osons": {
      "DOCUMENT": {
        "displayName": "User123",
        "email": "user123@example.com"
      },
      "OID": "ABCDEF123456",
      "CREATED": "2023-10-25T14:00:00Z",
      "LAST_MODIFIED": "2023-10-25T14:00:00Z",
      "VERSION": 1
    }
  }]
}

Example 17-5 Relational Model Read Output

{
  "ret": [{
    "osons": {
      "name": "Scott",
      "age": 1142568,
      "about": "Some data",
      "OID": "FB03C10200",
      "_id": 1,
      "parent_oid": "_docId",
      "_metadata": {
        "etag": "943EEC508908213D2D00FF375854BB48",
        "asof": "00000000000001234"
      }
    }
  }]
}

Supported Read Operations

You can perform the following read operations on documents:

Table 17-2 Read Operations

Operation Method Description
Read a Specific Document getDoc() Retrieves a specific document using its OID. Supports both document and relational models.
List Documents getDocs() Fetches all documents in a collection, optionally filtered by conditions.

Read a Specific Document

This operation retrieves a single document using its unique identifier within a collection.

The conceptual flow is:

  1. Specify the collection and document ID.

  2. Execute a getDoc operation.

  3. Validate existence and extract data.

Read All Documents in a Collection

This operation retrieves all documents within a specified collection path. This is useful for listing entities like users, recipes, or posts.

The conceptual flow is:

  1. Specify the collection path.

  2. Execute a getDocs operation.

  3. Iterate over the returned documents.

Query Capabilities and Semantics

Oracle Backend with Firebase APIs supports a wide range of query filters and modifiers:

Filters

These filters can be applied to fields within documents to retrieve matching results:

Modifiers

These modifiers allow developers to fine-tune their queries for performance and relevance:

Query Semantics

Queries are executed against collections or collection groups. Results are returned as shallow documents, meaning that nested subcollections must be queried separately. This design promotes modular data access and avoids unnecessary data transfer.

In a relational context, Oracle Backend with Firebase APIs uses metadata tables to determine primary and foreign key relationships. This information is used to construct join queries that simulate hierarchical document access. In a document context, queries operate directly on JSON documents and support flexible filtering and sorting.

Filtering with Conditions

Oracle Backend with Firebase APIs supports expressive filtering using conditional operators. These filters can be applied to fields within documents to narrow down results. The conditions array enables developers to filter documents based on field values.

Table 17-3 Supported Operators

Operator Description Example Use Case
== Equal to Find recipes where category == "Dessert"
!= Not equal to Exclude recipes where category != "Dessert"
> / < / >= / <= Numeric comparisons (Greater than / Less than / Greater than or equal to / Less than or equal to) Filter by views > 1000
array-contains Match array element Tags include "sweet"
array-contains-any Match any array element Tags include "sweet" or "baking"
in Match any field value in array Category is "Dessert" or "Snack"
not-in Exclude Values: Field value not in array Category is not "Dessert" or "Snack"

Example 17-6

"conditions": [
  { "field": "upd_by", "op": ">=", "value": "01/01/2023" },
  { "field": "upd_by", "op": "<=", "value": "11/01/2023" },
  { "field": "verified", "op": "==", "value": true }
]

Ordering and Pagination

To manage large datasets, Oracle Backend with Firebase APIs supports ordering and pagination modifiers:

Table 17-4 Ordering and Pagination Modifiers

Modifier Description
orderBy(field, direction) Sort results by a field (asc or desc)
limit(n)

Restrict result count

Use the limit field to control how many documents are returned. A value set as "limit": 0 means no limit is set. Setting limit can be useful for paginated user interfaces or infinite scroll implementations.

startAt(value) / endAt(value) Paginate by value range
startAfter(doc) / endBefore(doc) Paginate by document reference
array-contains-any Match any array element
in Match any field value in array
not-in Exclude Values: Field value not in array

Example Use Cases

Retrieve recipes created in 2025, ordered by creation date:

Ordering using explicitOrder

The explicitOrder array allows sorting results by one or more fields.

"explicitOrder": [
  { "field": "upd_by", "direction": "asc" },
  { "field": "priority", "direction": "desc" }
]

direction can be "asc" or "desc".

Collection Group and Join Queries

Collection Group Queries

A collection group allows querying across all subcollections with the same name, regardless of their parent document hierarchy. For example, query all notes subcollections under different recipes.

The following are the prerequisites for using collection group queries:

Join Queries

Join queries allow developers to combine data from multiple collections or relational duality views into a single result set. This is useful when related information is stored across different collections and needs to be queried together.

The following setup must be completed before using Join Queries:

For relation joins, currently, only INNER JOINs are supported. All joined tables must share a common key (USING).

In the following example, joins are applied in the order listed. Joins are not treated as actual collections (no docRef is returned for joined rows).

The following is the general workflow:

Example 17-7 Join Query

Suppose that the target collections are Cities collection and Employees collection, the join query request is as follows:

{
  "path": ["Cities"],
  "conditions": [
    { "field": "COUNTRY", "op": "=", "value": "USA" }
  ],
  "limit": "2",
  "joins": [
    {
      "collection": "Employees",
      "on": { "field": "CITY_ID", "op": "=", "value": "Cities.ID" }
    }
  ],
  "explicitOrder": [
    { "field": "POPULATION", "direction": "asc" }
  ],
  "aggregate": []
}

The resulting output is as follows:

{
  "ret": [
    {
      "osons": {
        "DOCUMENT": {
          "NAME": "NewYork",
          "COUNTRY": "USA",
          "POPULATION": 123455678,
          "EMPLOYEE": {
            "EmployeeID": "2",
            "FirstName": "John",
            "LastName": "Morrow",
            "Email": "Marston17@norton.net"
          }
        },
        "CREATED": "2025-01-24T08:03:27.014334",
        "LAST_MODIFIED": "2025-01-24T08:03:27.014334",
        "VERSION": 1,
        "OID": "2C6F2A7F590D231BE0631F965E6400A4"
      }
    }
  ]
}

Aggregation Functions

The aggregate array allows applying SQL-style aggregation functions on fields.

The supported functions are:

"aggregate": [
  { "field": "age", "func": "sum", "op_key": "sumofage" },
  { "field": "score", "func": "avg", "op_key": "avgscore" }
]

op_key is the alias used in the result for each aggregation.