When using DQL’s INSERT command, you can add new documents using JSON objects:
DQL
INSERT INTO your_collection_nameDOCUMENTS ([document1]),([document2]), ([document3]), ...[ON ID CONFLICT [FAIL | DO NOTHING | DO UPDATE | DO UPDATE_LOCAL_DIFF]]
INSERT INTO is the name of the collection from which you want to retrieve the data.
DOCUMENTS ([document1]), ([document2]), ([document3]), ... represent the documents being inserted.
Alternative: You can use VALUES instead of DOCUMENTS - they are functionally equivalent
[ ON ID CONFLICT [FAIL | DO NOTHING | DO UPDATE | DO UPDATE_LOCAL_DIFF]] is an optional clause that allows for defining a policy if the ID already exists in the local data store. The default is to throw an error (FAIL).
Both VALUES and DOCUMENTS keywords work identically in INSERT statements. You can use either based on your preference:
DQL
-- Using DOCUMENTSINSERT INTO cars DOCUMENTS (:car1), (:car2)-- Using VALUES (equivalent)INSERT INTO cars VALUES (:car1), (:car2)
Both syntaxes support:
Single or multiple documents
Parameters or literal objects
Arrays of documents
ON ID CONFLICT clauses
INITIAL keyword for default data
Mixing single documents and arrays in one statement (v5+): Any parameter in the VALUES or DOCUMENTS list can be either a single document object or an array of document objects. When a parameter resolves to an array, each element is inserted as a separate document.
DQL
INSERT INTO collection VALUES(:single),(:array)
With parameters {"single": {"a": 1}, "array": [{"a": 2}, {"a": 3}]}, this results in 3 documents being inserted.
In Ditto, excluding fields from your payload doesn’t remove the existing data from the system.To remove a specific field from a document, use an explicit UPDATE statement and UNSET that field. (See UPDATE)
ditto.store.execute( "INSERT INTO cars DOCUMENTS (:newCar)", Collections.singletonMap("newCar", Collections.singletonMap("color", "blue")));
var args = new Dictionary<string, object>();args.Add("newCar", new { color = "blue" });await ditto.Store.ExecuteAsync( "INSERT INTO cars DOCUMENTS (:newCar)", args);
Map<String, Map<String, String>> args = new HashMap<>();args.put("car1", Collections.singletonMap("color", "blue"));args.put("car2", Collections.singletonMap("color", "red"));ditto.store.execute( "INSERT INTO cars DOCUMENTS (:car1),(:car2)", args);
var args = new Dictionary<string, object>();args.Add("car1", new { color = "blue" });args.Add("car2", new { color = "red" });await ditto.Store.ExecuteAsync( "INSERT INTO cars DOCUMENTS (:car1),(:car2)", args);
std::map<std::string, std::map<std::string, std::string>> args;args["car1"] = {{"color", "blue"}};args["car2"] = {{"color", "red"}};auto result = ditto.get_store().execute( "INSERT INTO cars DOCUMENTS (:car1),(:car2)", args).get();
You can also insert multiple documents by passing an array of objects as a parameter. This is particularly useful when you have a dynamic list of documents to insert.
val cars = listOf( mapOf("color" to "blue", "year" to 2020), mapOf("color" to "red", "year" to 2021), mapOf("color" to "green", "year" to 2022))ditto.store.execute( "INSERT INTO cars VALUES (:cars)", mapOf("cars" to cars))
var cars = new List<object> { new { color = "blue", year = 2020 }, new { color = "red", year = 2021 }, new { color = "green", year = 2022 }};await ditto.Store.ExecuteAsync( "INSERT INTO cars VALUES (:cars)", new Dictionary<string, object> { { "cars", cars } });
When using array parameters, each object in the array will be inserted as a separate document. You can combine array parameters with literal document parameters in the same INSERT statement.
Starting with SDK 4.8, Ditto provides a convenient way to insert JSON-serialized documents using the deserialize_json() function. This allows you to directly insert string-encoded JSON data into your collections without manually parsing it first.
deserialize_json() also works in UPDATE statements to set fields from JSON strings. See UPDATE with deserialize_json for examples.
await ditto.store.execute( query: """ INSERT INTO cars DOCUMENTS (deserialize_json(:jsonData)) ON ID CONFLICT DO UPDATE """, arguments: [ "jsonData": "{\"_id\": \"123\",\"color\": \"blue\"}" ])
By default, the INSERT operation throws an error if an existing document with the same ID exists in the local Ditto store.However, Ditto allows some flexibility by allowing you to choose between ignoring the conflict (DO NOTHING) or updating existing documents (DO UPDATE) when a conflict occurs during an INSERT operation:
DQL
ON ID CONFLICT [FAIL | DO NOTHING | DO UPDATE | DO UPDATE_LOCAL_DIFF]
In this syntax:
FAIL (default) will cause an error to be thrown if a document with the same _id currently exists in the local data store.
DO NOTHING will make the statement succeed with no action taken.
DO UPDATE will perform a value update on every field in the provided document, even if the value is the same. This means all fields provided will be replicated to other peers regardless of whether the values actually changed.
DO UPDATE_LOCAL_DIFF (SDK 4.12+) will only update fields whose values differ from the existing document. This is more efficient than DO UPDATE when you want to avoid unnecessary replication of unchanged values.
Use DO UPDATE when you want to update all fields in the document regardless of whether the values have changed. This is useful when you want to ensure all fields are replicated to other peers, even if the values are the same as the existing document.For example, inserting or updating a car — if there is a conflict (ON ID CONFLICT), execute the DO UPDATE conflict resolution policy:
let newCar = [ "_id": "123", "color": "blue"]await ditto.store.execute( query: """ INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE """, arguments: [ "newCar": newCar ])
var newCar = mapOf( "_id" to "123", "color" to "blue")ditto.store.execute(""" INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE """, mapOf("newCar", newCar))
const newCar = { _id: "123", color: "blue",};await ditto.store.execute(` INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE`, { newCar });
ditto.store.execute( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE", Collections.singletonMap("newCar", Collections.singletonMap("color", "blue")),)
var args = new Dictionary<string, object>();args.Add("newCar", new { _id = "123", color = "blue" })await ditto.Store.ExecuteAsync( "INSERT INTO cars"+ " DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE", args);
struct Car { std::string _id; std::string color;};// ...std::map<std::string, Car> args;args["newCar"] = {"123", "blue"};auto result = ditto.get_store().execute( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE", args).get();
let query_result = ditto .store() .execute_v2(( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE", serde_json::json!({ "newCar": { "_id": "123", "color": "blue" } }), )).await?;
final newCar = { "_id": "123", "color": "blue",};await ditto.store.execute(""" INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE""", queryArgs: {"newCar": newCar},);
Use DO UPDATE_LOCAL_DIFF when you want to update only the fields that have actually changed. Unlike DO UPDATE, which updates every field regardless of whether the value changed, DO UPDATE_LOCAL_DIFF compares the incoming document against the existing local document and only updates fields with different values.This is useful when:
You want to minimize unnecessary replication traffic
You’re frequently re-inserting documents where most fields remain unchanged
You want to avoid triggering sync for unchanged data
let newCar = [ "_id": "123", "color": "blue", "mileage": 5000]await ditto.store.execute( query: """ INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF """, arguments: [ "newCar": newCar ])
var newCar = mapOf( "_id" to "123", "color" to "blue", "mileage" to 5000)ditto.store.execute(""" INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF """, mapOf("newCar", newCar))
const newCar = { _id: "123", color: "blue", mileage: 5000,};await ditto.store.execute(` INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF`, { newCar });
Map<String, Object> newCar = new HashMap<>();newCar.put("_id", "123");newCar.put("color", "blue");newCar.put("mileage", 5000);ditto.store.execute( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF", Collections.singletonMap("newCar", newCar));
var args = new Dictionary<string, object>();args.Add("newCar", new { _id = "123", color = "blue", mileage = 5000 })await ditto.Store.ExecuteAsync( "INSERT INTO cars"+ " DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF", args);
struct Car { std::string _id; std::string color; int mileage;};// ...std::map<std::string, Car> args;args["newCar"] = {"123", "blue", 5000};auto result = ditto.get_store().execute( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF", args).get();
let query_result = ditto .store() .execute_v2(( "INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF", serde_json::json!({ "newCar": { "_id": "123", "color": "blue", "mileage": 5000 } }), )).await?;
final newCar = { "_id": "123", "color": "blue", "mileage": 5000,};await ditto.store.execute(""" INSERT INTO cars DOCUMENTS (:newCar) ON ID CONFLICT DO UPDATE_LOCAL_DIFF""", queryArgs: {"newCar": newCar},);
INSERT allows you to set specific documents as default data using the INITIAL DOCUMENTS action.Initial documents are the documents inserted at the beginning of time and are viewed by all peers as the same INSERT operation. This allows multiple peers to independently initialize the same default data safely, so regardless of the individual peer’s starting point.
When inserting, the initial documents DO NOTHING if the document ID already exists in the local Ditto store. The ON ID CONFLICT policy cannot change this behavior.
DQL
INSERT INTO your_collection_nameINITIAL DOCUMENTS ([document])
In this syntax:
your_collection_name is the name of the collection from which you want to retrieve the data.
[document] represents the document.
For example, setting up default data by inserting the given car details as an initial document:
var newCar = mapOf( "_id" to "123", "color" to "blue")ditto.store.execute(""" INSERT INTO cars INITIAL DOCUMENTS (:newCar) """, mapOf("newCar", newCar))
val arguments = mapOf( "newCar" to mapOf( "_id" to "123", "properties" to mapOf( "color" to "blue", "mileage" to 3000 ) ) ))ditto.store.execute(""" INSERT INTO COLLECTION cars (properties MAP) DOCUMENTS (:newCar) """, arguments)