Data Types
This article provides a complete overview of the various data types you can use with your queries to retrieve, modify, and sync data in Ditto. In addition, you'll find an introduction to related concepts like conflict resolution strategies.
For more information and how-to instructions on using Ditto's dedicated query language: DQL, see the official Ditto Query Language guide.
The Ditto Query Language (DQL) includes the following data types that define basic data representation:
- REGISTER
- MAP
- ATTACHMENT
As the foundation of how Ditto exposes and models data, these data types leverage conflict-free replicated data type (CRDT) technology to ensure that no data inconsistencies occur as a result of concurrent modifications; that is, simultaneous edits made to the same data types in multiples local Ditto stores. (See Resolving Conflicts)
As illustrated on the right, data types encapsulate both the value to be stored — encoded using scalar types like string, boolean, and so on — and field‑specific metadata that defines the enforced merge strategy in conflict resolution. (See Representing Data)
The specific scalar type declared for a DQL type is referred to as the scalar subtype throughout the documentation.
The following table provides a quick overview of the DQL data types you can use to write queries, along with their guiding principles for conflict resolution, or merge strategy, a brief description, and a common usage scenario:
The REGISTER type is the default and most simple-to-use type. Other types should be used in very specific scenarios.
If you're new to CRDTs — the core technology enabling Ditto's advanced offline-first capabilities — and prefer learning by doing, see Jake Lazaroff's blog for a hands-on tutorial: "An Interactive Intro to CRDTs."
All data types —REGISTER, MAP, and ATTACHMENT— adhere to the causal consistency model when resolving concurrency conflicts.
The causal consistency model is a guarantee that if there is an operation that must happen before another operation — for example, events A and B, where B is a result of A — all peers agree upon and observe the same sequential order of these operations; as in, A always executes before B.
What distinguishes Ditto from other offline-first databases is its implementation of the causal consistency model. In Ditto's implementation, conflicts are automatically resolved, merged, and synced across peers without the need for coordination or validation from a centralized authority.
This model includes two merge strategies determined by DQL type:
- Last-write-wins — Inserts new or replaces existing data with the update made by the last writer. (See REGISTER and ATTACHMENT)
Each Ditto document is nested with a hash-stable tree structure that self-describes the data to be stored and provides the predetermined rules that ensure data consistency and accuracy. (See Document Model)
You can model data in a document as a REGISTER, MAP, or ATTACHMENT, providing flexibility in representing a wide range of information.
When you want to embed a hierarchical structure to represent complex parent‑children data structures within a document, you have the option to nest either a JSON object or a MAP. The decision between the two depends on your specific use case:
To represent embedded values with dependencies, like a GPS coordinate along with its corresponding address, structure your data in a JSON object as a scalar value in a REGISTER, which functions as a single entity for easier management:
The array type in Ditto acts as a REGISTER and therefore encapsulating values function as a single unit. The following utilization of the array type for the "coordinates" field in the MAP is a smart choice since both latitude and longitude values change simultaneously. (See REGISTER)
To represent embedded values with no dependencies; that is, you want the flexibility to update each key-value pair independently, structure your data as separate REGISTER fields in a MAP:
To represent highly complex data structures that necessitate establishing additional hierarchies, embed a MAP within another MAP:
Syncing large documents can significantly impact network performance.
The decision to use deeply embedded MAPS in a single document or opt for a flat model instead depends on your specific requirements, relationships between data, and tolerance for certain tradeoffs. For more information, see Evaluation Criteria.
The following graphic and corresponding table aim to demonstrate the distinct capabilities and versatility of each DQL type.
The REGISTER data type functions as the default in Ditto for scalar-encoded values. So any scalar-encoded values, including embedded JSON objects with a nested hierarchy serving as a single value, are automatically assumed to be of type REGISTER.
Item | Description |
---|---|
1 | A value can be any JSON-encoded primitive type: boolean, numeric, binary, string, array, NULL, and object ; as in a blob of key-value pairs that function as a single object (see item 2). |
2 | A hierarchical data structure comprised of multiple JSON-encoded fields that are nested within a larger JSON object and functions as a single object. When making an update to a JSON object, unlike a MAP, Ditto replaces the entire object with the updated version. |
3 | A hierarchical data structure containing two or more key-value pairs encoded using any data type — REGISTER, ATTACHMENT, or, to create complex structures, an embedded MAP. |
4 | The response object that Ditto returned to you after creating a new ATTACHMENT. You use the ATTACHMENT response object within your app's code to retrieve and display the file to the end user, as appropriate, as well as to update or delete the file. |
5 | The pointer that Ditto uses to reference the large file's storage location when fetching. You can use an ATTACHMENT for any file type, including binary data of 50 megapixels or more, such as an mp4 file, or a large document object featuring complex hierarchical structures. |
To use a DQL type other than a REGISTER — the default data type in Ditto — you must explicitly specify the type in your query; otherwise, Ditto defaults to the REGISTER type as follows.
Here is an example illustrating the same SELECT statement query explicitly expressed as a MAP structure. It specifies retrieval of the MAP structure storing the"features" collection with a "trim" field property set to a value of "standard":
For more information, see REGISTER, MAP, and ATTACHMENT.