CRUD Fundamentals
Ditto includes a robust query engine that allows you to perform various filter operations to carry out traditional create, read, update, and delete (CRUD) operations.
The Ditto SDK provides a comprehensive set of methods and functions to facilitate data interaction and perform a wide range of operations in your app:
- For read operations, use the find and observeLocal methods.
- For modifications, use the update, upsert, evict, and delete methods.
The following tables provides a high-level overview of the different ways you can perform CRUD in Ditto:
For more information, see Platform Manual > CRUD Operations.
Operation | Description |
Create | Using the upsert method, either insert a new document or updating an existing document for a given document ID. |
Read | Using either the find or observeLocal methods, retrieve documents based on the specific criteria you pass as parameters in your function. |
Update | Using either update or upsertmethods, write changes to Ditto. |
Delete | Using either remove or evict methods, delete data in Ditto. In addition, using a soft-delete pattern, indicate data as deleted without physically removing it from Ditto. |
Due to Ditto's conflict-free concurrency model, there is no concept of "insert." This is because each peer functions under the assumption that its write transaction already exists somewhere within the mesh network.
Therefore, Ditto uses a combined approach known as "upsert." This approach focuses on updating only the fields within the document that have changed, the delta. (See Sync Overview)
If all of the fields in the document are new, however, Ditto creates an entirely new document object. (See Platform Manual > Updating and Upserting)
With theupsert API method, you can execute any of the following actions in your app:
Action | Description |
Apply delta updates to existing documents | Write changes to only the specific fields within the document that are modified. (See Platform Manual > Upserting Delta Updates. |
Insert a document | If all of the fields are new, create a new document object. (See Platform Manual > Creating New Documents) |
Load initial data | Upsert and flag data you want to accessible to end users at app startup, such as sample chat messages from a central backend API. (See Platform Manual > Example Use Case: Upserting Initial Data) |
Supply a document ID | When creating a new document, if desired, you can assign your own unique identifier. Otherwise, Ditto automatically generates and assigns one for you. (See Platform Manual > Supplying a Custom ID) |
To retrieve data in Ditto, depending on your goals and use case, use any of the following query types:
- Local query — Using the find and findById methods, quickly get your own data in a one-time executable to your local Ditto store. For instance, call the findById method to target a specific document. Or if wanting to fetch one or more documents based on certain criteria and conditions, call thefind method instead.
- Live query — Using the observeLocal method, establish a listener to observe your local changes in real-time.
- Replication query — Using the subscribe method, keep your data consistent with other peers connected in the mesh network.
Similar to a traditional database query, the find and findById methods are based on a local query that fetches and returns all relevant documents.
Intended for quick access to data stored locally on its own device, such as a profile image, local queries are one-time executables that do not involve other peers connected in the mesh network.
A live query subscription is essentially a local query, but it includes an observeLocal method to establish continuous listening to real-time changes written to its own Ditto store.
Live queries are useful when you want to monitor changes from your local Ditto store and react to them immediately.
For instance, when your end user updates their own profile, you can asynchronously display the changes to the end user in real-time.
A replication query is executed asynchronously through the subscribe method on each remote peer connected within the mesh network.
This query specifies the data for which your Small Peer local Ditto store is interested in receiving updates. When remote peers make modifications to the data you've indicated interest in, they publish the changes back to you — the subscribing originating peer.
Rather than continuously polling for updates, which is resource-intensive and generally inefficient, the asynchronous listener you set up triggers only when the data matching your query undergoes changes in the Ditto store.
The following table provides an overview of the CRDTs and associated behavior for a given operation:
Operation | Description |
set register | Sets the value for a given field in the document. |
set map | Sets value for a given field in the map. |
remove register | Removes a value for a given field in the document. |
remove map | Removes a value for a given key in the map structure. |
replace with counter | Converts a number value for a given field into a counter. |
increment counter | Unlike a number, increments the counter by the given positive integer value. |
decrement counter | Unlike a number, decrements the counter by the given negative integer value. |
To update a single document, using the upsert method:
Specify the document collection you want to make an update to.
Pass your field changes.
Only delta changes are written to local Ditto stores; if the Ditto store is already up to date, the changes do not commit. For more information, see Sync Overview.
If you want to perform writes to multiple documents, start the transaction asynchronously to avoid blocking the main thread.
For example, in Swift pseudocode, use DispatchQueue.global, as demonstrated in the following snippet. (Although syntax differs in other languages, the concept remains the same.)
For more information, see the Platform Manual > Best Practices for CRUD.
Managing the amount of data stored and replicated across resource-constrained Small Peers interconnected in a bandwidth-limited mesh is crucial for maintaining optimal performance in a peer-to-peer environment.
In distributed database system architecture, you must strike a balance between data availability and system efficiency.
Depending on your use case, use either the evict method or the remove API method to implement memory management practices like automatic resource allocation, memory deallocation, cleaning and maintenance, upon many other tools to help optimize memory usage in your app.
If you need to ensure that, although deleted, the data remains recoverable, you can add a soft-delete pattern.