# MongoDB Data Modeling

## Steps to take

1. Identify workload
    
2. Map relationship
    
3. Apply design patterns
    
4. Optimization - creating indexes
    

## Identify workload

At this step, we mostly need to identify if our application is read or write-heavy and which resources are critical.

Example

| **Action** | **Type** | **Information** | **Frequency** | **Priority** |
| --- | --- | --- | --- | --- |
| Submit a new article | Write | author, text | 10 per day | High |
| Submit a comment on an article | Write | user, text | 1,000 per day (100 per article) | Medium |
| View an article | Read | article id, text, comments | 1,000,000 per day | High |
| View article analytics | Read | article id, comments, clicks | 10 per hour | Low |

## Data relationship

### Referencing or Embedding

Example of referencing

```json
// Referencing
// books
{
  "_id": "book1",
  "title": "MongoDB",
  "authors": ["author1", "author2"]
}

// authors
[
  { "author_id": "author1", "name": "Huy" },
  { "author_id": "author2", "name": "Steve" }
]
```

Example of embedding

```json
{
  "_id": "book1",
  "title": "MongoDB",
  "authors": [
    { "author_id": "author1", "name": "Huy" },
    { "author_id": "author2", "name": "Steve" }
  ]
}
```

### When to use which?

In MongoDB, **the recommended way to handle related data is to embed** it into a sub-document - retrieve information without **$lookup**. The other way is to use references.

👉 The golden rule: **Data that is accessed together should be stored together**

Let’s take a look at the above **books** and **authors** relationship

**Here are the guidelines**

* **Simplicity** - would keeping the pieces together lead to a simpler data model and code? =&gt; **Yes - Embed**
    
* **Go Together** - Do the pieces of information have a “has-a”, “contains” relationship? **Yes - Embed**
    
* **Query Automicity** - Does the app query the pieces of info together? **Yes - Embed**
    
* **Update Complexity** - Are the pieces of info updated together? **No - Reference**
    
    * We can update the book and author separately
        
* **Archival** - should the pieces of information be archived at the same time? **No - Reference**
    
* **Cardinality \*** - is there a high growth in the child side of the relationship? **No - Embed**
    
* **Data Duplication** - Would data duplication be too complicated to manage and undesired? **No - Embed**
    
* **Document Size** - Would the combined size take too much memory or transfer bandwidth? **No - Embed**
    
* **Document Growth** - would the embedded piece grow without bound? **No - Embed**
    
* **Workload** - are the pieces of info written at different times in a write-heavy workload? **No - Embed**
    
    * If we frequently update related data, then better to use a reference
        
* **Individuality** - for the child side, can the pieces exist by themselves without a parent? **No - Embed**
    
    * An author cannot exist in our app without a book
        

**👉 But mostly consider**

* Array size
    
* Update frequency of embedded data
    
* Whether the embedded entity is often queried independently
    

### One-to-one

**Example**: one company has one headquarters

**Embedded - recommended in this case** ✅

```json
{
  "_id": "publisher123",
  "name": "MongoDB Press",
  "street": "123 Data Lane",
  "city": "San Francisco",
  "state": "CA",
  "country": "USA",
  "zip": "94107"
}

// it's better to group - nested object
{
  "_id": "publisher123",
  "name": "MongoDB Press",
  "headquarters": {
    "street": "123 Data Lane",
    "city": "San Francisco",
    "state": "CA",
    "country": "USA",
    "zip": "94107"
  }
}
```

**Reference**

**Option 1**: Array of references within the parent document

✅ Use when - the app primarily reads publisher documents

```json
// publishers
{
  "_id": "publisher123",
  "name": "MongoDB Press",
  "headquarter_id": "hq1"
}

// headquarters
{
  "_id": "hq1",
  "street": "123 Data Lane",
  "city": "San Francisco",
  "state": "CA",
  "country": "USA",
  "zip": "94107"
}
```

**Option 2:** a child document to reference the parent document

✅ Use when - the app primarily reads headquarters documents

```json
// publishers
{
  "_id": "publisher123",
  "name": "MongoDB Press"
}

// headquarters
{
  "_id": "hq1",
  "publisher_id": "publisher123",
  "street": "123 Data Lane",
  "city": "San Francisco",
  "state": "CA",
  "country": "USA",
  "zip": "94107"
}
```

### One-to-Many

**Example**: one printed book has many reviews

**Embedded**

Good when

* No duplication of information - i.e, in this case, review can be attached to one book only
    
* The option on many sides cannot exist by itself - i.e, review cannot exist without the printed book
    

Bad when

* Children are an unbounded array =&gt; it can make the document super large
    

**Option 1:** As an array

```json
{
  "_id": "book0456",
  "title": "Practical MongoDB Aggregations",
  "author": "Paul Done",
  "reviews": [
    {
      "user_id": "user0956",
      "title": "Lorem Ipsum",
      "review_text": "dolor sit amet...",
      "rating": 3
    },
    {
      "user_id": "user0345",
      "title": "Ut enim",
      "review_text": "ad minim veniam...",
      "rating": 4
    }
  ]
}
```

**Option 2:** As an object

```json
{
  "_id": "book0456",
  "title": "Practical MongoDB Aggregations",
  "author": "Paul Done",
  "reviews": {
    "user0956": {
      "title": "Lorem Ipsum",
      "review_text": "dolor sit amet...",
      "rating": 3
    },
    "user0345": {
      "title": "Ut enim",
      "review_text": "ad minim veniam...",
      "rating": 4
    }
  }
}
```

**Reference**

**Option 1**: Array of references to child documents in parent document

Use when: The list of children is *small* and often accessed *together with* the parent

```json
// books
{
  "_id": "book0456",
  "title": "Practical MongoDB Aggregations",
  "author": "Paul Done",
  "reviews": [
    "review001",
    "review002"
  ]
}

// reviews
[
  {
    "_id": "review001",
    "user_id": "user0956",
    "title": "Lorem Ipsum",
    "review_text": "dolor sit amet...",
    "rating": 3
  },
  {
    "_id": "review002",
    "user_id": "user0345",
    "title": "Ut enim",
    "review_text": "ad minim veniam...",
    "rating": 4
  }
]
```

**Option 2**: a child document to reference the parent document **\- recommended in this case due to an unbounded array** ✅

Use when:

* The number of children is *large* or *grows unbounded*.
    
* You rarely need all the children at once.
    

```json
// books
{
  "_id": "book0456",
  "title": "Practical MongoDB Aggregations",
  "author": "Paul Done"
}

// reviews
[
  {
    "_id": "review001",
    "book_id": "book0456",
    "user_id": "user0956",
    "title": "Lorem Ipsum",
    "review_text": "dolor sit amet...",
    "rating": 3
  },
  {
    "_id": "review002",
    "book_id": "book0456",
    "user_id": "user0345",
    "title": "Ut enim",
    "review_text": "ad minim veniam...",
    "rating": 4
  }
]
```

### Many-to-many

**Example**: a book has many authors, and an author can write many books

**Embedded - recommended in this case, check the “When to use which” section above** ✅

Notice that here we have data duplication. However, it’s not always an issue

**Option 1**: As an array

```json
{
  "_id": "book0008",
  "title": "Mastering MongoDB 7.0",
  "authors": [
    {
      "author_id": "author0021",
      "name": "Elie Hannouch"
    },
    {
      "author_id": "author0087",
      "name": "Malak Abu Hammad"
    },
    {
      👉 "author_id": "author0046",
      "name": "Rachelle Palmer"
    }
  ]
}

// another book
{
  "_id": "book0017",
  "title": "Building Rich and Resilient Applications with MongoDB",
  "authors": [
    {
      👉 "author_id": "author0046",
      "name": "Rachelle Palmer"
    }
  ]
}
```

**Option 2**: As an object

```json
{
  "_id": "book0008",
  "title": "Mastering MongoDB 7.0",
  "authors": {
    "author0021": {
      "name": "Elie Hannouch"
    },
    "author0087": {
      "name": "Malak Abu Hammad"
    },
    "author0046": {
      "name": "Rachelle Palmer"
    }
  }
}
```

**Reference**

**Option 1**: Array of references to child documents in parent document

```json
// books
[
  {
    "_id": "book0008",
    "title": "Mastering MongoDB 7.0",
    "authors": [
      "author0021",
      "author0087",
      👉 "author0046"
    ]
  },
  {
    "_id": "book0017",
    "title": "Building Rich and Resilient Applications with MongoDB",
    "authors": [
      👉 "author0046"
    ]
  }
]

// authors
[
  {
    "_id": "author0021",
    "name": "Elie Hannouch"
  },
  {
    "_id": "author0087",
    "name": "Malak Abu Hammad"
  },
  {
    "_id": "author0046",
    "name": "Rachelle Palmer"
  }
]
```

**Option 2**: a child document to reference the parent document

```json
// books
[
  {
    "_id": "book0008",
    "title": "Mastering MongoDB 7.0"
  },
  {
    "_id": "book0017",
    "title": "Building Rich and Resilient Applications with MongoDB"
  }
]

// authors
[
  {
    "author_id": "author0021",
    "name": "Elie Hannouch",
    // not that unlike the one-to-many
    // this is an array
    👉 "books": ["book0008"]
  },
  {
    "author_id": "author0087",
    "name": "Malak Abu Hammad",
    👉 "books": ["book0008"]
  },
  {
    "author_id": "author0046",
    "name": "Rachelle Palmer",
    "books": ["book0008", "book0017"]
  }
]
```

## Resources

* [https://www.mongodb.com/docs/manual/data-modeling/](https://www.mongodb.com/docs/manual/data-modeling/)
    
* [https://learn.mongodb.com/learning-paths/data-modeling-for-mongodb](https://learn.mongodb.com/learning-paths/data-modeling-for-mongodb)
    
* [https://www.mongodb.com/docs/manual/data-modeling/concepts/embedding-vs-references/](https://www.mongodb.com/docs/manual/data-modeling/concepts/embedding-vs-references/)
