Introduction

In MongoDB, embedded documents (also known as subdocuments) allow you to store related data within a single document structure. This is a powerful feature that can simplify data retrieval and improve performance by reducing the need for joins, which are common in relational databases.

Key Concepts

  1. Embedded Documents: These are documents nested within other documents. They allow for a more natural representation of hierarchical data.
  2. Denormalization: Unlike SQL databases, MongoDB encourages denormalization, where related data is stored together in a single document.
  3. Atomicity: Operations on a single document, including embedded documents, are atomic. This means that updates to a document are fully completed or not done at all.

When to Use Embedded Documents

  • One-to-One Relationships: When one document is closely related to another and is always accessed together.
  • One-to-Many Relationships: When a document contains a list of related items that are typically accessed together.
  • Performance Considerations: When embedding can reduce the number of read operations and improve query performance.

Practical Example

Let's consider a scenario where we have a collection of users, and each user has multiple addresses. Instead of creating a separate collection for addresses, we can embed the addresses directly within the user document.

Example Document Structure

{
  "_id": "user123",
  "name": "John Doe",
  "email": "[email protected]",
  "addresses": [
    {
      "type": "home",
      "street": "123 Main St",
      "city": "Anytown",
      "state": "CA",
      "zip": "12345"
    },
    {
      "type": "work",
      "street": "456 Corporate Blvd",
      "city": "Bigcity",
      "state": "NY",
      "zip": "67890"
    }
  ]
}

Explanation

  • User Document: The main document representing a user.
  • Addresses: An array of embedded documents, each representing an address.

Inserting an Embedded Document

db.users.insertOne({
  "_id": "user123",
  "name": "John Doe",
  "email": "[email protected]",
  "addresses": [
    {
      "type": "home",
      "street": "123 Main St",
      "city": "Anytown",
      "state": "CA",
      "zip": "12345"
    },
    {
      "type": "work",
      "street": "456 Corporate Blvd",
      "city": "Bigcity",
      "state": "NY",
      "zip": "67890"
    }
  ]
});

Querying Embedded Documents

To find a user by their home address city:

db.users.find({
  "addresses.city": "Anytown"
});

Updating an Embedded Document

To update the street of the home address for a specific user:

db.users.updateOne(
  { "_id": "user123", "addresses.type": "home" },
  { $set: { "addresses.$.street": "789 New St" } }
);

Deleting an Embedded Document

To remove the work address from a specific user:

db.users.updateOne(
  { "_id": "user123" },
  { $pull: { "addresses": { "type": "work" } } }
);

Practical Exercises

Exercise 1: Insert a User with Embedded Documents

Task: Insert a new user with the following details:

  • Name: Jane Smith
  • Email: [email protected]
  • Addresses:
    • Home: 789 Elm St, Smalltown, TX, 54321
    • Work: 1010 Industrial Rd, Metropolis, IL, 98765

Solution:

db.users.insertOne({
  "name": "Jane Smith",
  "email": "[email protected]",
  "addresses": [
    {
      "type": "home",
      "street": "789 Elm St",
      "city": "Smalltown",
      "state": "TX",
      "zip": "54321"
    },
    {
      "type": "work",
      "street": "1010 Industrial Rd",
      "city": "Metropolis",
      "state": "IL",
      "zip": "98765"
    }
  ]
});

Exercise 2: Query Users by Embedded Document Field

Task: Find all users who have a work address in the city of "Metropolis".

Solution:

db.users.find({
  "addresses.city": "Metropolis"
});

Exercise 3: Update an Embedded Document

Task: Change the zip code of Jane Smith's home address to "11111".

Solution:

db.users.updateOne(
  { "name": "Jane Smith", "addresses.type": "home" },
  { $set: { "addresses.$.zip": "11111" } }
);

Exercise 4: Delete an Embedded Document

Task: Remove the home address from John Doe's document.

Solution:

db.users.updateOne(
  { "_id": "user123" },
  { $pull: { "addresses": { "type": "home" } } }
);

Common Mistakes and Tips

  • Over-Embedding: Avoid embedding too much data, which can lead to large documents and performance issues. Use references if the embedded data grows too large.
  • Atomic Operations: Remember that updates to a single document, including embedded documents, are atomic. This can simplify your application logic.
  • Indexing: Consider indexing fields within embedded documents to improve query performance.

Conclusion

Embedded documents in MongoDB provide a flexible and efficient way to model related data. By understanding when and how to use embedded documents, you can design schemas that are both performant and easy to work with. In the next topic, we will explore references and how they can be used to model relationships between documents in MongoDB.

© Copyright 2024. All rights reserved