Platform Manual
CRUD Operations

Finding and Observing

This article provides an overview of essential methods for document retrieval, query formulation, and realtime monitoring.

Just like with conventional database querying, you execute query operations to fetch one or more documents that satisfy specific criteria and conditions, as well as to set up listeners, referred to as subscriptions, for the data you're interested in watching.

Find Method

Use the find and findById methods for executing single queries against the local Ditto store. Once invoked, these methods retrieve documents based on the query you provided as an argument:

Additionally, when working with dynamic changes, for ease, convenience, and flexibility, you can define and use values within a top-level args variable for your queries, as opposed to needing to separately adjust each individual query structure and conditions change.

For more information, see $args for Dynamic Data.

Finding by Query

The Find method executes a single query against the Ditto store, targeting to retrieve one or more documents within a given collection based on certain criteria.

You can search for documents within a collection against a wide range of criteria, from very broad conditions to more specific filters.

For instance, you can look for documents in a collection based on general conditions, such as "find all documents in the 'cars' collection with the field 'color' set to 'blue'."

Or narrow the focus of your search and use various filter options, including comparison operators (like greater than, less than), logical operators (AND, OR), upon many other tools Ditto offers for precisely adjusting your filters. For an overview of the filter options you can use to create complex search criteria in your queries, see Ditto Basics > Query Syntax.

In your find function, indicate the document collection to query and define a condition that determines which documents to return.

Swift
Kotlin
JS
Java
C#
C++
Rust


For example, the following find function, when invoked, searches the cars collection for documents with the field color set to blue:

Swift
Kotlin
JS
Java
C#
C++
Rust


Finding By Document ID

The Ditto query engine supports various filter operations for optimal data retrieval.

As the basis of data organization and access in Ditto, the query engine indexes the document _id so you can quickly and precisely access your data.

The first set of fields within each document uniquely identifies the data that its document object encodes. When grouped in a collection, this _id serves as the primary key identifying the document in the collection.

Each document must be assigned a unique identifier. When invoking the upsert method to create a new document, unless manually supplied, Ditto automatically generates and assigns the new document a 128‑bit Universally Unique Identifier (UUID).

For instructions on how to fetch a document by _id, see any of the following as appropriate:

  • Default UUID: If you did not supply a custom document ID, see String ID Lookup for instructions on retrieving a document by its Ditto-generated and -assigned UUID.
  • Custom string: If you provided a string value for the _id parameter when calling the Upsert API during document creation, see String ID Lookup.
  • Custom JSON blob object: If you provided two or more embedded fields for the _id parameter when calling the Upsert API during document creation, see Composite ID Lookup.

Retrieving by String ID

Fetch a single document by its primary key: the document _idfield by invoking the Find By ID method.

Swift
Kotlin
JS
Java
C#
C++
Rust


The following snippet demonstrates a Find By ID operation that, once called, searches for the document assigned the 123456 unique identifier:

Swift
Kotlin
JS
Java
C#
C++
Rust


Retrieving by Composite ID


Swift
Kotlin
JS
Java
C#
C++
Rust


Using $args for Dynamic Data

Handling dynamic-changing data introduces challenges that impact your end-user experience, as well as the maintainability, security, and performance of your app.


Swift
Kotlin
JS
Java
C#
C++
Rust


For example, the following snippet illustrates a local query using the string "color == $args.color":

Swift
Kotlin
JS
Java
C#
C++
Rust


Limiting and Sorting Results

In addition to using various operators and string formats to construct conditions in your queries, you can also control the results that are returned from calls to the Find and Find By ID functions:

Limit Method: Restricting Results

Restrict the number of results returned by your query by using the Limit method to specify the number of results you want to return.

Swift
Kotlin
JS
Java
C#
C++
Rust


The following snippet demonstrates a Limit operation set for 100 query results:

Swift
Kotlin
JS
Java
C#
C++
Rust


Sort Method: Arranging Results

Sort the results by a specific order using the Sort method. With the Sort method, you specify the field to match and the desired order for arranging the matching query results, as follows:

By default, queries that do not include a sort operation filter by document ID.

Swift
Kotlin
JS
Java
C#
C++
Rust


The following snippet demonstrates a sort operation on the miles field with results arranged in ascending order:

Swift
Kotlin
JS
Java
C#
C++
Rust


Limit and Sort Methods in a Single Executable

To enhance query efficiency, you can perform both sort and limit operations within a single query, as follows:

Swift
Kotlin
JS
Java
C#
C++
Rust


Observe Local Method

In scenarios where you want to continuously watch changes occurring to your local Ditto store in realtime, use live queries. With a live query, you signal which changes you're interested in watching and define the callback function that you want Ditto to trigger in response.

Additionally, you can incorporate both time-based and state-based replication techniques into your app's design patterns. For more information, see Use Cases > State-Based Replication and Time-Based Replication.

For organization and management, you can create a Live Query object to store a single live query or multiple live queries, as well as a custom class that encapsulates the logic for managing your live queries.

Swift
Kotlin
JS
Java
C#
C++
Rust


Creating Live Queries

To set up a single live query, as demonstrated in the following snippet:

For instructions on creating multiple live queries stored in a single LiveQuery object, see Creating a Batch of Live Queries.

  1. In the top-most scope of your app, declare a Live Query object.
  2. Specify the event you're interested in watching; for example, the cars collection where the color is black.
  3. Using the Observe Local method, define the subsequent liveQuery callback function that you want Ditto to execute in your app. For more information, see Constructing Live Query Callback Functions, as follows.
Swift
Kotlin
JS
Java
C#
C++
Rust


For example, the following snippet demonstrates an observeLocal method that monitors changes in the cars collection where the color is "blue".

Once the changes occur, the total number of documents displays to the end user.

Swift
Kotlin
JS
Java
C#
C++
Rust


Constructing Live Query Callback Functions

If you're not using a Reactive framework, consider reacting to changes from a Live Query Event object. A Live Query Event object is a dynamic query that, as changes occur, automatically updates Ditto in realtime.

Reactive frameworks — like React, Jetpack Compose, and SwiftUI — provide tooling and various features to make UI development more efficient and help you build responsive apps with minimal effort.

These Reactive frameworks do this by abstracting away the low-level details of updating UI, managing state, and rendering components; eliminating the need to manually implement a diffing algorithm. For more information, see React's official documentation > Learn React.

Events Argument

A LiveQuery callback consists of two arguments: docs and event. The docs argument specifies your collection and the event argument identifies which documents have changed.

The following table provides an overview of events in Ditto:

Event Type

Description

Initial

The first event that will be delivered (and delivered only once).

Update

The event to return each time the results of your live query change. It contains information about the set of documents that previously matched the query before the update, along with information about what documents have been inserted, removed, updated, or moved (upserted), as part of the set of matching documents.

Creating a Batch of Live Queries

To create multiple live queries stored in a single LiveQuery object that you can use to add live queries, remove specific ones, and stop all live queries at once, using either an array or a map, create a custom class that encapsulates your management logic.

For more information about batching live queries, see LiveQueryEvent in the SDK Setup Guides > Ditto API reference for your language. (For a complete listing, see Directory of Ditto Technical Documentation.)

For more information about Ditto arrays and maps, see Data Types.

Canceling Live Queries

To cancel a live query, call cancel or stop on the live query object you initially set up to establish the live query.

Once canceled, the live query stops receiving updates.

Swift pseudocode

Swift pseudocode