---
title: Complex Structures
slug: v4-5/document-model/complex-structures
docTags: 
createdAt: 2023-10-06T15:01:06.007Z
---

When it comes to managing complex data structures, choosing the right pattern can significantly impact the efficiency and effectiveness of your app.

# Bad Pattern: Large Documents

You can embed a map in another map to create an embedded `map` comprised of multiple, hierarchical levels. For more information, see [MAP](docId\:aSkVPbYIxDZ0NqQJ4UET0).

For example, consider a `people` collection that contains documents with the following schema:

::Image[]{src="https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/qwuv59DhKOS3OBfV1viYF_badpatternschema.png" size="30" width="761" height="534" position="flex-start" showCaption="false"}

Such a schema translates to a document with a nested map `cars` where each car can be arbitrarily large:

```json
{
  "name": "Susan",
  "age": 43,
  "cars": {
    "abc123": {
      "make": "Hyundai",
      "color": "red",
      "mileage": 13000
   },
    "def456": {
     "make": "Jeep",
     "color": "blue",
     "mileage": 34000
  }
}
```

## Results in Slow Replication Performance

The previous approach results in slow replication performance as follows:

- In scenarios with a limited internet connection or exclusive use of Bluetooth Low Energy (LE) for syncing across connected peers, replicating documents that contain large amounts of data experiences a slowdown.&#x20;

  For instance, relying solely on Bluetooth LE for a document of typical size results in a maximum replication rate of 20 KB per second. Consequently, a document of 250 KB or more may take 10 seconds or more to replicate for the first time between devices.

- A slow replication rate causes a loading spinner to display to your end users until the replication process completes.&#x20;


:::hint{type="info"}
The reason that a slow replication rate causes a loading spinner during the replication process is that the callback is unable to render the returned data.&#x20;

The end‑to‑end replication process requires breaking down documents into smaller parts before syncing them across the mesh. Only once the client receives all the smaller parts and reconstructs them, is the document returned.
:::

## Alternative: Multiple Smaller Documents

Instead of using a single document to encode all of your large datasets, use a series of smaller documents. For more information, see [Good Pattern: Flat Models](./#good-pattern-flat-models).

:::hint{type="warning"}
Documents that exceed 5 MB do not sync with other connected peers.
:::

:::hint{type="info"}
If a document exceeds 250 KB in size,  `stdout` warning prints to the console.
:::

# Good Pattern: Flat Models

Unless required for your particular use case and requirements, instead of opting for a deeply embedded `map` structure,&#x20;

Ditto uses a combination of the collection name and the document ID to sync and query documents. Collections serve as an index for a set of related documents, allowing you to establish foreign relationships between them by referencing the document ID.

For example, consider a `people` collection and a `cars` collection:&#x20;

::Image[]{src="https://api.archbee.com/api/optimize/qoRkNxW5fJ81r_NqVpc8C/e8CtCZ1NykU9J2ct0YhSx_goodpatternschema.png" size="30" width="761" height="1239" position="flex-start" showCaption="false"}

In the previous example, each car has an owner — represented by the `_id.ownerId` field — which relates to the person's document ID.&#x20;

:::hint{type="warning"}
Since the document `_id` is immutable, only use the flat model in situations where you have static identifiers within your foreign-key relationship. If you use the flat model
:::

In the `people` collection:

```json
{
  "_id": "abc123",
  "name": "Susan",
  "age": 31
}
```

In the `cars` collection:

```json
{
  "_id": {
    "id": "def456",
    "ownerId": "abc123" 
  },
  "make": "Hyundai",
  "color": "red",
}
```

