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 following tables provides a high-level overview of the different ways you can perform CRUD in Ditto:
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 upsert methods, 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. |
For detailed information on CRUD, see Platform Manual > CRUD Operations.
For an overview of the various operators and path navigations you can use to construct sophisticated queries in your app, see Platform Manual > Query Syntax.
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 the upsert 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 be 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 you want to fetch one or more documents based on certain criteria and conditions, call thefind method instead. (See Local Queries)
- Live query — Using the observeLocal method, establish a listener to observe your local changes in realtime. (See Live Queries)
- Replication query — Using the subscribe method, keep your data consistent with other peers connected in the mesh network. (See Replication Queries)
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.
For more information and how-to instructions, see Platform Manual > CRUD Operations and Finding and Observing.
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 realtime.
For more information and how-to instructions, see Platform Manual > CRUD Operations and Finding and Observing.
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 an 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:
If you want to perform writes to multiple documents, start the transaction asynchronously to avoid blocking the main thread.
For example, in Swift, use DispatchQueue.global, as demonstrated in the following snippet.
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 system architecture, you must strike a balance between data availability and system efficiency:
- The greater the amount of data replicated across connected peers, the more timely offline read access becomes.
- The fewer the number of data replicated across connected peers, the less likelihood that peer devices run out of disk space and experience memory leaks.
Depending on your use case, use either the evict or remove 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.
Given these technical tradeoffs, use the Subscribe and Eviction methods carefully to implement your tradeoff design decisions:
- To sync more data across peers connected in the mesh, call Subsribe.
- To remove data stored locally on a peer device, call Evict.
Evicting a document is not permanent; as long as there is at least one active subscription with a query that includes an evicted document, that document will reappear as soon as it is available in the mesh.
You can signify that data is irrelevant for peer-to-peer replication but should still be retained locally by adding isSafeToEvict to the document field property tree.
To ensure that small peers continue syncing documents that are considered relevant, include isSafeToEvict == false in their subscription queries and then use some means to inform clients to flag any documents that they consider irrelevant.
That way, only the document that a client sets to 'true' is prevented from syncing.
Once flagged, the clients purge the irrelevant documents from their caches, all the while normal transactional operations continue without interruption.
The Remove method, once invoked, permanently deletes specified documents from the local datastore as well as all other connected peers.
Use the Remove method with extreme caution; invoking Remove results in irreversible data loss.
If you need to ensure that, although deleted, the data remains recoverable, you can add a soft-delete pattern to the document property tree:
For comprehensive information on deleting data in Ditto, see Platform Manual > Evicting and Removing.