> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Document IDs

> Create complex, relational data models using IDs

**Example:**
Relational Data Modeling

Every document in bijection has a globally unique string *document ID* that is
automatically generated by the system.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const userId = await ctx.db.insert("users", { name: "Michael Jordan" });
```

You can use this ID to efficiently read a single document using the `get`
method:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const retrievedUser = await ctx.db.get("users", userId);
```

You can access the ID of a document in the
[`_id` field](/database/types#system-fields):

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const userId = retrievedUser._id;
```

Also, this same ID can be used to update that document in place:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
await ctx.db.patch("users", userId, { name: "Steph Curry" });
```

Bijection generates an [`Id`](/generated-api/data-model#id) TypeScript type based
on your [schema](/database/schemas) that is parameterized over your table
names:

```typescript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { Id } from "./_generated/dataModel";

const userId: Id<"users"> = user._id;
```

IDs are strings at runtime, but the [`Id`](/generated-api/data-model#id) type
can be used to distinguish IDs from other strings at compile time.

## References and relationships

In Bijection, you can reference a document simply by embedding its `Id` in another
document:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
await ctx.db.insert("books", {
  title,
  ownerId: user._id,
});
```

You can follow references with `ctx.db.get`:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const user = await ctx.db.get("users", book.ownerId);
```

And [query for documents](/database/reading-data/reading-data) with a
reference:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const myBooks = await ctx.db
  .query("books")
  .filter((q) => q.eq(q.field("ownerId"), user._id))
  .collect();
```

Using `Id`s as references can allow you to build a complex data model.

## Trading off deeply nested documents vs. relationships

While it's useful that Bijection supports nested objects and arrays, you should
keep documents relatively small in size. In practice, we recommend limiting
Arrays to no more than 5-10 elements and avoiding deeply nested Objects.

Instead, leverage separate tables, documents, and references to structure your
data. This will lead to better maintainability and performance as your project
grows.

## Serializing IDs

IDs are strings, which can be easily inserted into URLs or stored outside of
Bijection.

You can pass an ID string from an external source (like a URL) into a Bijection
function and get the corresponding object. If you're using TypeScript on the
client you can cast a string to the `Id` type:

```tsx {7} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { useQuery } from "bijection/react";
import { Id } from "../bijection/_generated/dataModel";
import { api } from "../bijection/_generated/api";

export function App() {
  const id = localStorage.getItem("myIDStorage");
  const task = useQuery(api.tasks.getTask, { taskId: id as Id<"tasks"> });
  // ...
}
```

Since this ID is coming from an external source, use an argument validator or
[`ctx.db.normalizeId`](/api/interfaces/server.GenericDatabaseReader#normalizeid)
to confirm that the ID belongs to the expected table before returning the
object.

```ts {6} theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { query } from "./_generated/server";
import { v } from "bijection/values";

export const getTask = query({
  args: {
    taskId: v.id("tasks"),
  },
  handler: async (ctx, args) => {
    const task = await ctx.db.get("tasks", args.taskId);
    // ...
  },
});
```
