---
title: CRUD Fundamentals
slug: v4-5/basics/crud-fundamentals
docTags: 
createdAt: 2023-08-03T16:12:29.513Z
---

Ditto Query Language (DQL) — the dedicated query language you'll use to perform various filter operations to carry out traditional `CREATE`, `READ`, `UPDATE`, and `DELETE` (CRUD) database operations — is a familiar SQL‑like syntax designed specifically for Ditto's edge sync features that enable the platform's offline-first capabilities. 

:::hint{type="info"}
For a list of API references by language, see the [Directory of Ditto Technical Documentation](docId\:K0F9I2pXyjM3k9uwmAOaL) in the *Platform Manual*.&#x20;
:::

To execute CRUD operations, call the Ditto SDK's `execute` API method as follows:

All modification operations in Ditto are performed using the `execute` API method against the `ditto.store`:

:::CodeblockTabs
```swift
let result = try await ditto.store.execute(query: /* query */, arguments: /* arguments */);
```

```kotlin
var result = ditto.store.execute(/* query */, /* arguments */)
```

```javascript
const result = await ditto.store.execute(/* query */, /* arguments */)
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
  /* query */,
  /* arguments */,
  /* continuation */);
```

```csharp
var result = await ditto.Store.ExecuteAsync(/* query */, /* arguments */);
```

```cpp
auto result = ditto.get_store().execute(/* query */, /* arguments */).get();
```

```rust
let result = ditto.store().execute(/* query */, /* arguments */);
```
:::

# Overview

The following table provides a high-level overview of the different ways you can perform CRUD in Ditto:

| **Operation** | **Description**                                                                                                                                                                                                  |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CREATE`      | Using the `INSERT` statement, either insert a new document or update an existing document for a given document ID.  (See [Creating](./#creating))                                                                |
| `READ`        | Using the `SELECT` statement, retrieve documents based on the specific criteria you pass as parameters in your function. (See [Reading](./#reading))                                                             |
| `UPDATE`      | Using the `UPDATE` method, write changes to Ditto. (See [Updating](./#updating))                                                                                                                                 |
| `DELETE`      | Using the `EVICT` method, remove local data from your store. (See [Deleting](./#deleting))<br />In addition, using a *soft-delete pattern*, indicate data as deleted without physically removing it from Ditto.  |

:::hint{type="info"}
For detailed information on CRUD, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN).

For an overview of the various operators and path navigations you can use to construct sophisticated queries in your app, see [Ditto Query Language](docId\:e3UQqeqVzvOTjlS2xfDFl).
:::

# Creating

To create a new document in your local Ditto store, call `INSERT`. Following is an example of how to perform an `INSERT` operation using Ditto's SDK:

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

```kotlin
ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  mapOf("newCar" to mapOf("color" to "blue")))
```

```javascript
await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  { newCar: { color: "blue" } });
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "INSERT INTO cars DOCUMENTS (:newCar)",
    Collections.singletonMap("newCar", Collections.singletonMap("color", "blue")),
);
```

```csharp
var args = new Dictionary<string, object>();
args.Add("newCar", new { color = "blue" });

await ditto.Store.ExecuteAsync(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  args);
```

```cpp
std::map<std::string, std::map<std::string, std::string>> args;
args["newCar"] = {{"color", "blue"}};

auto result = ditto.get_store().execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  args).get();
```

```rust
use serde::Serialize;

#[derive(Serialize)]
struct Args {
  newCar: Car,
}
#[derive(Serialize)]
struct Car {
  color: String
}

// ...

let args = Args {
  newCar: Car {
    color: "blue".to_string()
  },
};

ditto.store().execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  Some(args.into())); 
```
:::

For more information and how-to instructions, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN) > [CREATE](docId\:QsOasGYrr0l0DYdXy77cA).

# Reading

To retrieve data in Ditto, depending on your goals and use case, use any of the following query types:

- Single Execution query — Using the `execute` method and a `SELECT` query, execute a single read operation. (See [Single Execution Query](./#single-execution-query))

- Store Observer query — Using the `addObserver` method, establish a listener to watch your local changes in realtime. (See [Store Observer Query](./#store-observer-query))

## Single Execution Query

With the `execute` API method and `SELECT` query, search for documents within your local Ditto store:

:::CodeblockTabs
```swift
let result = await ditto.store.execute(query: "SELECT * FROM cars")
```

```kotlin
val result = ditto.store.execute("SELECT * FROM cars")
```

```javascript
const result = await ditto.store.execute("SELECT * FROM cars");
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "SELECT * FROM cars",
    new Continuation<>() {
        @NonNull
        @Override
        public CoroutineContext getContext() {
            return EmptyCoroutineContext.INSTANCE;
        }

        @Override
        public void resumeWith(@NonNull Object o) {
            if (o instanceof Result.Failure) {
                // Handle failure
            }
        }
    }
);
```

```csharp
var result = await ditto.Store.ExecuteAsync("SELECT * FROM cars");
```

```cpp
auto result = ditto.get_store().execute("SELECT * FROM cars").get();
```

```rust
let result = ditto.store().execute("SELECT * FROM cars", None);
```
:::

For more information and how-to instructions, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN) > [READ](docId\:Yt3VDNkWaEhBu1PjTjzVL).

## Store Observer Query

When you need to actively monitor changes within your local Ditto store and respond to them immediately; for example, watching updates to end-user profiles, use a *store observer*.&#x20;

A store observer is a DQL query that runs continuously and, once Ditto detects relevant changes, asynchronously triggers the callback function you defined when you set up your store observer. For instance, when the end user updates their profile, display the profile changes to the end user in realtime.

Following is a snippet demonstrating how to establish a store observer in Ditto:

:::CodeblockTabs
```swift
let observer = ditto.store.registerObserver(
  query: "SELECT * FROM cars"){ result in /* handle change */ };
```

```kotlin
val observer = ditto.store.registerObserver("SELECT * FROM cars") { result ->
  /* handle change */ };
```

```javascript
const changeHandler = (result) => {
  // handle change
}
const observer = ditto.store.registerObserver(
  "SELECT * FROM cars",
  changeHandler);
```

```java
DittoStoreObserver observer = ditto.store.registerObserver(
    "SELECT * FROM cars",
    result -> {
        // handle change
    }
);
```

```csharp
// Without Arguments
var result = await ditto.Store.RegisterObserver(
  "SELECT * FROM cars",
  (result) => {
    // handle change
  });

// With Arguments
var result = ditto.Store.RegisterObserver(
  "SELECT * FROM cars",
  (result) => {
    // handle change
  });

```

```cpp
auto observer = ditto.get_store().register_observer(
  "SELECT * FROM cars",
  [&](QueryResult result) { /* handle change */ });
```

```rust
let observer = ditto.store().register_observer(
  "SELECT * from cars",
  None,
  move |result: QueryResult| {
    // handle change
  })
```
:::

For more information and how-to instructions, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN) > [READ](docId\:Yt3VDNkWaEhBu1PjTjzVL).

# Updating

With the `UPDATE` statement, you can update fields within one or more documents in your local Ditto store.

For example, executing an `UPDATE` operation within the `cars` collection, changing the color to `'blue'` and the mileage to `3001` in documents where the `_id` field is `'123'`:

:::CodeblockTabs
```swift
try await ditto.store.execute("""
  UPDATE cars
  SET color = 'blue'
  WHERE _id = '123'
  """);
```

```kotlin
ditto.store.execute("""
  UPDATE cars
  SET color = 'blue'
  WHERE _id = '123'
  """)
```

```javascript
await ditto.store.execute(`
  UPDATE cars
  SET color = 'blue'
  WHERE _id = '123'`)
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
  "UPDATE cars SET color = 'blue' WHERE _id = '123'",
  new Continuation<>() {
    @NonNull
    @Override
    public CoroutineContext getContext() {
      return EmptyCoroutineContext.INSTANCE;
    }

    @Override
    public void resumeWith(@NonNull Object o) {
      if (o instanceof Result.Failure) {
        // Handle failure
      }
    }
  }
);
```

```csharp
await ditto.Store.ExecuteAsync(
  "UPDATE cars SET color = 'blue' WHERE _id = '123'");
```

```cpp
ditto.get_store().execute(
  "UPDATE cars SET color = 'blue' WHERE _id = '123'").get();
```

```rust
ditto.store().execute(
  "UPDATE cars SET color = 'blue' WHERE _id = '123'",
  None); 
```
:::

For more information and how-to instructions, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN) > [UPDATE](docId\:WbVB_Hd0z6EBzelk5zm9y).

# Deleting

Data storage management is essential for preventing unnecessary resource usage, which affects not only performance but also battery life and overall end-user experience.&#x20;

Call the `Evict` method to clear one or more documents from the local Ditto store. Once invoked, the documents are no longer accessible by local queries; however, they remain accessible from other peers connected in the mesh.&#x20;

`EVICT` can be used with soft-delete patterns to safely coordinate the deletion of data across peers.

The following snippet shows how to write a basic `EVICT` operation to purge the document with an `_id` field of `'123'` from the local Ditto store:&#x20;

:::CodeblockTabs
```swift
await ditto.store.execute("EVICT FROM cars WHERE _id = '123'");
```

```kotlin
ditto.store.execute("EVICT FROM cars WHERE _id = '123'")
```

```javascript
await ditto.store.execute("EVICT FROM cars WHERE _id = '123'");
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "EVICT FROM cars WHERE _id = '123'",
    new Continuation<>() {
        @NonNull
        @Override
        public CoroutineContext getContext() {
            return EmptyCoroutineContext.INSTANCE;
        }

        @Override
        public void resumeWith(@NonNull Object o) {
            if (o instanceof Result.Failure) {
                // Handle failure
            }
        }
    }
);
```

```csharp
ditto.Store.ExecuteAsync("EVICT FROM cars WHERE _id = '123'");
```

```cpp
ditto.get_store().execute("EVICT FROM cars WHERE _id = '123'").get();
```

```rust
ditto.store().execute("EVICT FROM cars WHERE _id = '123'", None);
```
:::

For more information and how-to instructions, see [CRUD Operations](docId\:LBRSIPPkeZdqTGBM4i5NN) > [DELETE](docId\:F-5Iy165eOFkhDbAT1Zd7).

