Database Operations

Syncing data across the mesh is an entirely separate process from CRUD, involving replicating documents across different databases rather than interacting with a single datastore.

Creating Documents

To insert a document, call the EXECUTE API method against the ditto.store object and include an INSERT INTO query that specifies the document to be inserted.

Ditto does not support nesting documents within documents. Instead, opt for a foreign-key relationship by referencing the document ID. For more information, see Relationships.

For example, the following snippet demonstrates how to insert a new document with a single field “color” set to “blue”:

await ditto.store.execute(
    query: "INSERT INTO cars DOCUMENTS (:newCar)",
    arguments: ["newCar": ["color": "blue"]]);

If desired, supply a document ID in your creation request; otherwise, Ditto automatically generates and assigns one.

Inserting Multiple Documents

To efficiently create multiple documents, use the INSERT INTO operation and specify multiple query parameters, as follows:

await ditto.store.execute(
  query: "INSERT INTO cars DOCUMENTS (:doc1), (:doc2)",
  arguments: [
    "doc1": ["color": "blue"],
    "doc2": ["color": "red"]
  ]);

Identifying Documents

Unless manually supplied, Ditto automatically generates and assigns the new document a 128‑bit Universally Unique Identifier (UUID).

The document identifier is represented as _id and serves as the primary key for the document.

Retrieving Document IDs

To access the IDs of the documents affected by the INSERT INTO operation, call the mutatedDocumentIDs method on the result object after the insertion like this:

let result = await ditto.store.execute(
  query: "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: [
    newCar: ["color": "blue"]
  ]);

// "507f191e810c19729de860ea"
print(result.mutatedDocumentIDs()[0])

Supplying String IDs

When creating a document, you can assign it a custom ID. This custom ID can be generated using a single string value or a combination of two or more string values.

This flexibility in structuring document identifiers allows you to customize document IDs to your specific requirements, use cases, or standard naming conventions.

The following snippet demonstrates a new document assigned the custom ID “123”.

let result = await ditto.store.execute(
  query: "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: [
    newCar: ["_id": "123", "color": "blue"]
  ]);

// "123"
println(result.mutatedDocumentIDs().first())

Following is the new 123 document that results:

{
  "_id": "123",
  "color": "blue"
}

Forming Composite Keys

The following demonstrates combining the vin and make fields to form a composite key:

let arguments = [
  newCar: [ "_id": [vin: "123", make: "Toyota"], "color": "blue"]
];

let result = await ditto.store.execute(
  query: "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: arguments);

// "{vin: "123", make: "Toyota"}"
print(result.mutatedDocumentIDs()[0])

Creating Attachments

There are two separate steps in the process of creating an attachment:

1

Create the attachment in the Ditto store. (Initiating ATTACHMENT Objects)

2

Reference the returned attachment token in a document. (Referencing Attachment Tokens)

For a realworld usage scenario, see either the demo chat app for iOS or Android in the getditto > demoapp-chat GitHub repository.

Initiating ATTACHMENT Objects

To create the ATTACHMENT object that encodes the actual contents of the file to store externally, call the newAttachment method on the store namespace.

let newAttachment = try await ditto.store.newAttachment(path: filePath)

Adding Optional Metadata

If desired, enclose extra information about the attachment, such as name and description. This metadata is useful for attachment fetching operations.

If you want to include information about the attachment, such as the attachment filename, as shown in the following snippet, a description, and other relevant details, enclose it in a metadata object as key-value pairs.

let metadata = ["name": "image.png"]
let newAttachmentWithMetadata = try await ditto.store.newAttachment(path: filePath, metadata: metadata)

For example, in the following snippet, the metadata property encapsulates the name of the attachment, as well as its description:

let metadata = ["name": "japan.png", "description": "This is an image of a sunset in Japan."];
let newAttachmentWithMetadata = try await ditto.store.newAttachment(path: filePath, metadata: metadata)

Inserting Attachments in a Document

After creating and storing a new attachment object in Ditto, you receive an attachment token as part of the response.

The following snippet demonstrates how to create a new document object containing a new attachment, and then insert it into the cars collection:

// First, create the attachment
let metadata = ["name": "image.png"]
let attachment = try await ditto.store.newAttachment(path: filePath, metadata: metadata)

// Then, create a new document object and store the attachment on the `my_attachment` field.
let newDocument: [String: Any] = ["_id": "123", "my_attachment": attachment]

// Finally, insert the new document into the collection.
// Note that the `my_attachment` field needs to be declared as an `ATTACHMENT` data type.
// When explicitly declaring types for your fields, the COLLECTION keyword is mandatory.
let result = await ditto.store.execute(
  query: "INSERT INTO COLLECTION docs (my_attachment ATTACHMENT) DOCUMENTS (:newDocument)",
  arguments: ["newDocument": newDocument]);

Creating MAPs

There are two ways to create a MAP structure within a document:

  • In an INSERT operation — Create a new document and nest it with this set of fields.
  • In an UPDATE operation — If the MAP does not exist, create it. (See UPDATE)

To represent a highly complex data structure in a MAP, consider embedding it with an additional MAP. Embedding a MAP within a MAP establishes an additional hierarchy.

The decision to use deeply embedded MAPS in a single document or opt for a flat model depends on your requirements, relationships between data, and tolerance for certain tradeoffs.

The flat model is a simple, non‑embedded structure in which you spread your data across multiple, separate documents.

Inserting to Create a MAP

When inserting a new document in Ditto, you can define a field as a MAP and include the structure of key-value pairs nested within it — a two-in-one approach. For example:

let arguments: [String: Any] = [
  "newCar": [
    "_id": "123",
    "properties": [
      "color": "blue",
      "mileage": 3000
    ]
  }
];

await ditto.store.execute(
  query: "INSERT INTO COLLECTION cars (properties MAP) DOCUMENTS (:newCar)",
  arguments: arguments);

You can also create MAPs within a document after the fact using an UPDATE operation.

In the UPDATE approach, you set the structure of key-value pairs and specify the document ID to update.

For example, this statement creates a MAP structure, adding key-value pair of “color is red” to the properties MAP for the document with the ID 123 in the cars collection:

DQl
UPDATE COLLECTION cars (properties MAP)
   SET properties -> ( color = 'red' )
 WHERE _id = '123'

Was this page helpful?