---
title: DELETE
slug: v4-6/crud/delete
docTags: 
createdAt: 2023-07-28T20:04:36.552Z
---

This article provides an overview and how-to instructions for deleting documents using the `EVICT` DQL operation.

- [Evict Method](./#evicting-data)
- [Coordinating Evictions](./#coordinating-evictions)
- [Soft-Delete Pattern](./#soft-delete-pattern)
- [Considerations](docId:4_UQdIXL6XndDH0BjZYWt)

# Evicting Data

The `EVICT` method, once invoked, immediately removes the specified document from the local Ditto store, making it inaccessible by local queries.

For complete DQL syntax, see [EVICT](docId\:ksPbI9CsHPdud0iyuow9E).

Although the document you evicted is removed from the **local** Ditto store, the document stored within **remote** Ditto stores persists.

To prevent the evicted data from reappearing on the screen in a single flicker, make sure to stop subscriptions **before** you call `EVICT`; otherwise, the subscription remains active and even if you reset the data in your end-user environment, the evicted data momentarily reappears.

:::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 complete DQL syntax, see *Ditto Query Language (DQL)&#x20;*> [EVICT](docId\:HGhl3Q-v3v19FZKCvaC2m)

## Evicting Multiple Documents in a Collection

The `EVICT` operation functions based on a condition, allowing updates to multiple documents simultaneously.&#x20;

For example, the following snippet, once executed, purges all `blue` cars stored in the local Ditto store. &#x20;

:::CodeblockTabs
```swift
let result = await ditto.store.execute(
  "EVICT FROM cars WHERE color = 'blue'");

result.mutatedDocumentIDs.forEach() { print($0) }
```

```kotlin
var result = ditto.store.execute("EVICT FROM cars WHERE color = 'blue'")

result.mutatedDocumentIDs().forEach { id ->
    println(id)
}
```

```javascript
const result = await ditto.store.execute(
  "EVICT FROM cars WHERE color = 'blue'");

console.log(result.mutatedDocumentIDs())
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "EVICT FROM cars WHERE color = 'blue'",
    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(
  "EVICT FROM cars WHERE color = 'blue'");
    
result.MutatedDocumentIds.ForEach(id => Console.WriteLine(id));
```

```cpp
auto result = ditto.get_store().execute(
  "EVICT FROM cars WHERE color = 'blue'").get();

for (DocumentId id : result) {
    std::cout << id.to_string();
}
```

```rust
let result = ditto.store().execute(
  "EVICT FROM cars WHERE color = 'blue'",
  None);

for id in &result {
    println!("{}", id.to_string());
}
```
:::

### Referencing Previously Evicted Documents

Once removed, you can reference the evicted document using the `mutatedDocumentIDs` method on the `result`.

## Using Evict with Sync Subscriptions

To clear documents with active subscriptions, you must first cancel the relevant subscription before calling the `EVICT` method.

:::hint{type="warning"}
You must manage subscriptions and evictions carefully.&#x20;

If subscriptions are not properly managed prior to executing evictions, you may inadvertently disrupt the intended state, resulting in inconsistencies and unexpected behavior. For instance, the eviction process failing and the document persisting in the local Ditto store.
:::

For example, if you have an active subscription for fetching `'blue'` cars and you subsequently evict the document with the ID `'123456'` that matches the replication query, connected peers reinstate it in your local Ditto store. In other words, the document does not clear and remains available in the local Ditto store.&#x20;

## Timing Subscriptions and Evictions

The frequency for removing locally stored documents depends on your app's use case:

- To avoid the risk of depleting local storage capacity, consider evicting data frequently, such as once per day (if not more).
- To enhance offline datastore resiliency, you can implement app logic that allows your end users to choose which data to evict from their environments.

In addition, take a balanced approach when using the Subscribe and Evict methods. Consider the advantages and drawbacks of each method and use them as appropriate for specific needs and requirements.

Key considerations for using Subscription and Eviction methods include:

- Use Subscribe to sync more data across connected peers in the mesh; however, be mindful of potential increased network usage, which may degrade sync performance.

- Use Evict to manage local storage capacity and improve performance by routinely purging data stored locally.

## Coordinating Evictions

If you want to indicate that a batch of documents are irrelevant and, although they are to be retained, should *not* sync across peers, add the `isSafeToEvict` field to the document property tree. Then, use a method to alert clients to flag any documents they consider irrelevant.

:::CodeblockTabs
Ditto Document

```json
{
  "_id": "abc123",
  "color": "red",
  "mileage": 40000,
  "isSafeToEvict": true,
  "createdAt": "2023-05-22T22:24:24.217Z"
}
```
:::

To ensure that peers continue replicating documents that are considered relevant,  incorporate `isSafeToEvict == false` into their sync subscription query.&#x20;

This approach restricts replication only to documents that peers mark as `'true'` for `isSafeToEvict`. Once flagged, the peers clear irrelevant documents from their caches, all the while normal transactional operations continues without interruption.&#x20;

:::CodeblockTabs
```swift
await ditto.store.execute("EVICT FROM cars WHERE isSafeToEvict = true");
```

```kotlin
ditto.store.execute("EVICT FROM cars WHERE isSafeToEvict = true").await()
```

```javascript
ditto.store.execute("EVICT FROM cars WHERE isSafeToEvict = true");
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "EVICT FROM cars WHERE isSafeToEvict = true",
    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 isSafeToEvict = true");
```

```cpp
ditto.get_store().execute(
  "EVICT FROM cars WHERE isSafeToEvict = true").get();
```

```rust
ditto.store().execute("EVICT FROM cars WHERE isSafeToEvict = true", None);
```
:::

# Deleting Attachments

Attachment data stored within the Small Peer Ditto store is automatically garbage collected on a 10-minute cadence when no longer referenced.

:::hint{type="info"}
Attachments currently can only be deleted by way of garbage collection.
:::

Unlike documents, attachments cannot be explicitly deleted on their own. Instead, you modify the document containing the attachment token referencing it.

The following table provides an overview of the various ways you can indirectly delete attachments:

| **Approach** | **Description**                                                                              |
| ------------ | -------------------------------------------------------------------------------------------- |
| `UPDATE`     | Update the document to remove the associated attachment token.                               |
| `EVICT`      | Delete the entire document, including the associated attachment token, from the Ditto store. |

The storage mechanism Small Peers use to store data, including blob data, depends on  the platform:

- If running in the browser or a server-based system, data is stored in its Random Access Memory (RAM).
- If running on a mobile device like an iPhone, data is stored on its local filesystem.

# Soft-Delete Pattern

If you need a data recovery option, instead of permanently removing the data from the local Ditto store like `EVICT`, opt for a *soft-delete pattern.&#x20;*

A soft-delete pattern is a way to flag data as inactive while retaining it for various requirements, such as archival evidence, reference integrity, prevention of potential data loss due to end-user error, and so on.

## Adding a Soft-Delete Flag

To add a soft-delete pattern, set the `isArchived` field value to `true`:

:::CodeblockTabs
Ditto Document

```json
{
  "_id": "123",
  "color": "blue",
  "isArchived": true // add this field
}
```
:::

## Querying Non-Archived Documents

To query to monitor documents that are  `NOT` archived, establish a live query where `isArchived` is set to `false`, and then construct your live query callback.&#x20;

For example, the following code demonstrates searching for documents that are unarchived:

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

```kotlin
var result = ditto.store.execute("""
  SELECT *
  FROM cars
  WHERE isArchived = false
  """)
```

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

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "SELECT * FROM cars WHERE isArchived = false",
    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 WHERE isArchived = false");
```

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

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

## Removing Soft-Delete Flag

To remove the flag and reactivate the document, set the `isArchived` field to `false`:&#x20;

:::CodeblockTabs
```swift
await ditto.store.execute("""
  UPDATE cars
  SET isArchived = false
  WHERE _id = '123'
  """)
```

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

```javascript
await ditto.store.execute(`
  UPDATE cars
  SET isArchived = false
  WHERE _id = '123'`);
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "UPDATE cars SET isArchived = false 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 isArchived = false WHERE _id = '123'");
```

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

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

***

# Considerations

To mitigate the risk of memory leaks, performance degradation, crashes, data loss, and, if applicable, reduced battery life, it is critical that you implement a thoughtful memory management strategy in your app.

Depending on your use case, use either the Evict method or apply the soft-delete pattern to implement tools to help optimize memory usage in your app.&#x20;

When planning your approach to memory management in your app, use the following criteria to help you during the decision-making process:

| **Consideration**              | **Recommendation**                                                                                                                                                                                                               |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Access frequency and relevance | Ensure memory is allocated only to the most relevant and frequently accessed documents by establishing an automatic process that evicts documents that are:<br />* Accessed less frequently
* No longer relevant or needed&#x20; |
| Time-based data                | Establish an automatic process to evict or remove time-based data older than a minimum of seven days. (Until expired, time-based data remains accessible by way of local queries.)                                               |
| Permanent data loss            | If documents are evicted from a local peer and don't exist on any other peer this data is lost and is unrecoverable.<br />                                                                                                       |

## Access Frequency and Relevance Considerations

In peer-to-peer system design, there are technical tradeoffs between the amount of data synced across peers and the timeliness of access to synced data:

- The greater the amount of data synced, the more timely offline read access becomes. That is, database resilience in offline scenarios increases when more documents are being synced across distributed peers.

- The fewer the number of documents replicated, the less the likelihood that peer devices run out of disk space and experience memory leaks, and the performance of the peer-to-peer mesh network that interconnects them degrades.

:::hint{type="info"}
For considerations on using the Evict and Subscribe methods, see [Timing Subscriptions and Evictions](./#timing-subscriptions-and-evictions).
:::

:::hint{type="info"}
For advanced concepts related to design tradeoffs in distributed system architecture, see [Cloud-Optional Design](docId:2sZGHoGrwFXAIpaZ8sfAF).
:::

