---
title: Identifiers
slug: v4-8/document-model/identifiers
docTags: 
createdAt: 2023-08-14T14:25:32.351Z
---

Every document has an identifier field `_id`. The identifier field serves as the primary key for the document and can be either auto-generated or custom-assigned.

Following are the main features and qualities associated with the `_id` field:&#x20;

| **Document Identification**  | The document `_id` field serves as the primary key identifying the document in Ditto.                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Customizable Identifier:** | If preferred, you can customize the \_id as a string or JSON‑object. (See [Custom Document Identifier](./#custom-document-identifier)) |
| **Retrieval by&#x20;**`_id`  | You can fetch a document by its identifier. For more information, see Fetching a Document by `_id`.                                    |

# Auto-Generated Document Identifier

When inserting a document, unless manually supplied, Ditto automatically generates and assigns the new document a 128‑bit Universally Unique Identifier (UUID) to the `_id` field.

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

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

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

// "507f191e810c19729de860ea"
println(result.mutatedDocumentIDs().first())
```

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

// "507f191e810c19729de860ea"
console.log(result.mutatedDocumentIDs()[0])
```

```java
DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "INSERT INTO cars DOCUMENTS (:newCar)",
    Collections.singletonMap("newCar", Collections.singletonMap("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
            }
        }
    }
);

// "507f191e810c19729de860ea"
System.out.println(result.mutatedDocumentIDs()[0]);
```

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

var result = await ditto.Store.ExecuteAsync(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  insertArgs);
  
// "507f191e810c19729de860ea"
result.MutatedDocumentIds.ForEach(id => Console.WriteLine(id));
```

```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();

// "507f191e810c19729de860ea"
std::cout << result.mutated_document_ids()[0].to_string();
```

```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()
  },
};

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

// "507f191e810c19729de860ea"
println!("{}", result.mutated_document_ids()[0].to_string())
```

```dart
final result = await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: {
    "newCar": {"color": 'blue'},
  },
);


// "507f191e810c19729de860ea"
print(result.mutatedDocumentIDs.first);
```
:::

***

# Custom Document Identifier

If supplying your own document ID, you can encode your value in a `string` or, if forming a composite key, a JSON-object.&#x20;

:::hint{type="warning"}
You can configure a custom document ID only at the time of document creation.&#x20;

Once a document is created, to ensure consistency and uniqueness throughout the platform, the unique identifier that either Ditto automatically generated and assigned or you manually assigned becomes permanent and cannot be changed at a later time.
:::

Following are a few key principles for handling IDs in Ditto:

- Do not include personally identifiable information (PII) in IDs
- IDs should be immutable; that is, unchangeable once assigned and permanent
- If an ID is formed by multiple fields, referred to as a *composite key*, those fields are not individually indexed

## Supplying a Custom String Identifier

The following snippet demonstrates creating a new document assigned the string value `123`.

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

// "123"
print(result.mutatedDocumentIDs()[0])
```

```kotlin
var result = ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  mapOf("newCar" to mapOf("_id" to "123", "color" to "blue")))
  
// "507f191e810c19729de860ea"
println(result.mutatedDocumentIDs().first())
```

```javascript
const newCar = {
  _id: "123",
  color: "blue"
}

const result = await ditto.store.execute(`
  INSERT INTO cars
  DOCUMENTS (:newCar)`,
  { newCar });

// "123"
console.log(result.mutatedDocumentIDs()[0])
```

```java
Map<String, String> newCar = new HashMap<>();
newCar.put("_id", "123");
newCar.put("color", "blue");

DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "INSERT INTO cars DOCUMENTS (:newCar)",
    Collections.singletonMap("newCar", newCar),
    new Continuation<>() {
        @NonNull
        @Override
        public CoroutineContext getContext() {
            return EmptyCoroutineContext.INSTANCE;
        }

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

// "123"
System.out.println(result.mutatedDocumentIDs()[0]);
```

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

var result = await ditto.Store.ExecuteAsync(
  "INSERT INTO your_collection_name DOCUMENTS (:newCar)",
  insertArgs);
  
// "123"
result.MutatedDocumentIds.ForEach(id => Console.WriteLine(id));
```

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

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

// "123"
std::cout << result.mutated_document_ids()[0].to_string();
```

```rust
use serde::Serialize;

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

// ...

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

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

// "123"
println!("{}", result.mutated_document_ids()[0].to_string())
```

```dart
final newCar = {
  "_id": "123",
  "color": "blue"
};

final result = await ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  arguments: { "newCar": newCar },
);

// "123"
print(result.mutatedDocumentIDs.first);
```
:::

## Forming a Composite Key Identifier

The decision to opt for a composite key depends on your specific use case. Following are typical use cases for forming a composite key:

- To implement additional logic to handle (or prevent) duplicate writes.

- To simplify queries and enhance efficiency in the querying process.

To form a composite key, set the `_id` to a JSON object when inserting a new document.

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

:::CodeblockTabs
```swift
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])
```

```kotlin
var result = ditto.store.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  mapOf(
    "newCar" to mapOf(
      "_id" to mapOf(
        "vin" to "123",
        "make" to "Toyota"
      ),
      "color" to "blue"
  )))
  
// "{vin: "123", make: "Toyota"}"
println(result.mutatedDocumentIDs().first())
```

```javascript
const newCar = {
  _id: {
    vin: "123",
    make: "Toyota"
  },
  color: "blue"
}
const result = await ditto.store.execute(`
  INSERT INTO cars
  DOCUMENTS (:newCar)`,
  { newCar });

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

```java
Map<String, String> newCarId = new HashMap<>();
newCarId.put("vin", "123");
newCarId.put("make", "Toyota");
Map<String, Object> newCar = new HashMap<>();
newCar.put("_id", newCarId);
newCar.put("color", "blue");

DittoQueryResult result = (DittoQueryResult) ditto.store.execute(
    "INSERT INTO cars DOCUMENTS (:newCar)",
    Collections.singletonMap("newCar", newCar),
    new Continuation<>() {
        @NonNull
        @Override
        public CoroutineContext getContext() {
            return EmptyCoroutineContext.INSTANCE;
        }

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

// "{vin: "123", make: "Toyota"}"
System.out.println(result.mutatedDocumentIDs()[0]);
```

```csharp
var newId = new { vin: "123", make: "Toyota"};
var insertArgs = new Dictionary<string, object>();
insertArgs.Add("newCar", new { _id = newId, color = "blue" });

var result = await ditto.Store.ExecuteAsync(
  "INSERT INTO your_collection_name DOCUMENTS (:newCar)",
  insertArgs);
  
// "{vin: "123", make: "Toyota"}"
result.MutatedDocumentIds.ForEach(id => Console.WriteLine(
  System.Text.Json.JsonSerializer.Serialize(id)));
```

```cpp
struct CarId {
  std::string vin;
  std::string make;
};
struct Car {
  CarId _id;
  std::color String;
};

std::map<std::string, Car> args;
args["newCar"] = {{"123", "Toyota"}, "blue"};

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

// "{vin: "123", make: "Toyota"}"
std::cout << result.mutated_document_ids()[0].to_string();
```

```rust
struct Args {
  newCar: Car,
}
struct CarId {
  vin: String,
  make: String
}
struct Car {
  _id: CarId,
  color: String
}

// ...

let args = Args {
  newCar: Car {
    _id: CarId {
      vin: "123".to_string(),
      make: "Toyota".to_string()
    },
    color: "blue".to_string()
  },
};

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

// "{vin: "123", make: "Toyota"}"
println!("{}", result.mutated_document_ids()[0].to_string())
```

```dart
final newCar = {
  "_id": {
    "vin": "123",
    "make": "Toyota"
  },  
  "color": "blue"
};

final result = await ditto.execute(
  "INSERT INTO cars DOCUMENTS (:newCar)",
  { "newCar": newCar },
);

// "{vin: "123", make: "Toyota"}"
print(result.mutatedDocumentIDs.first);
```
:::

***

# Fetching a Document by \_id

:::::VerticalSplit{layout="left"}
:::VerticalSplitItem
Retrieve a document by its identifier (`_id`):
:::

::::VerticalSplitItem
:::CodeblockTabs
DQL

```sql
SELECT *
FROM cars
WHERE _id = '123'
```
:::
::::
:::::

:::::VerticalSplit{layout="left"}
:::VerticalSplitItem
If querying a composite key identifier, use dot (.) notation:
:::

::::VerticalSplitItem
:::CodeblockTabs
DQL

```sql
SELECT *
FROM cars
WHERE _id.model = 'Toyota'
```
:::
::::
:::::

For more information, see [IDs, Paths, Strings, and Keywords](docId:4Y_JMJedQeq0-0uDNcJcQ) and [Operator Expressions](docId\:ASTjGLPVpQpApCy6K0yfd) in *Ditto Query Language*.
