Querying Documents

Learn about different query operators ($eq, $gt, $lt, $in, etc.) and how to construct complex queries to retrieve specific documents.


MongoDB Essentials: Querying Embedded Documents

Understanding Embedded/Nested Documents

In MongoDB, embedded documents (also known as nested documents) are documents contained within another document. They're a powerful way to model hierarchical data and represent relationships between entities without the need for joins, as often required in relational databases.

Consider this example of a document representing a product:

 {
  _id: ObjectId("6543210fedcba98765432100"),
  name: "Gaming Laptop",
  price: 1200,
  details: {
    processor: "Intel Core i7-13700H",
    memory: "16GB DDR5",
    storage: {
      type: "SSD",
      capacity: "1TB"
    },
    graphics: "NVIDIA GeForce RTX 4060"
  }
} 

In this example, the details field is an embedded document containing information about the laptop's specifications. The storage field is itself another embedded document nested within details.

Querying Embedded Documents

MongoDB provides flexible ways to query embedded documents using dot notation. This allows you to access specific fields within the nested structure.

1. Matching on a Field Within an Embedded Document

To find documents where a specific field within an embedded document matches a value, use dot notation in your query filter.

For example, to find all products with a processor of "Intel Core i7-13700H", you'd use the following query:

 db.products.find({ "details.processor": "Intel Core i7-13700H" }) 

This query targets the processor field inside the details embedded document.

2. Matching on an Entire Embedded Document

You can also match on an entire embedded document. However, the embedded document in your query must be an *exact* match for the embedded document in the stored data, including field order.

For example:

 db.products.find({
  details: {
    processor: "Intel Core i7-13700H",
    memory: "16GB DDR5",
    storage: {
      type: "SSD",
      capacity: "1TB"
    },
    graphics: "NVIDIA GeForce RTX 4060"
  }
}) 

This query will only return documents where the `details` field *exactly* matches the given document. It is generally more reliable to use dot notation for matching specific fields.

3. Querying Deeply Nested Documents

Dot notation can be used to access fields at any level of nesting. For example, to find all products with SSD storage:

 db.products.find({ "details.storage.type": "SSD" }) 

This query reaches into the details document, then into the storage document to target the type field.

Retrieving Specific Fields from Nested Documents (Projections)

You can use projections to return only specific fields from the top-level document and the embedded document(s). This improves performance by reducing the amount of data transferred.

To retrieve the product name and the processor information, use the following query:

 db.products.find(
  {},
  { name: 1, "details.processor": 1, _id: 0 }
) 

In this query:

  • The first argument {} specifies an empty filter, meaning we want to retrieve all documents.
  • The second argument { name: 1, "details.processor": 1, _id: 0 } is the projection.
  • name: 1 includes the name field in the results.
  • "details.processor": 1 includes the processor field from the details embedded document.
  • _id: 0 excludes the _id field, which is included by default.

The result will look like this:

 [
  { name: "Gaming Laptop", details: { processor: "Intel Core i7-13700H" } },
  ...
] 

Notice that only the specified fields are returned, and the rest of the details document is omitted.

Retrieving Entire Embedded Documents in Projections

You can include the entire embedded document.

 db.products.find(
    {},
    {name:1, details:1, _id:0}
) 

This query will return the name and the entire details field.

Combining Queries and Projections

You can combine filtering and projections to retrieve only the documents that match specific criteria and include only the desired fields. For instance, to find laptops with "SSD" storage and return only the name and storage type:

 db.products.find(
  { "details.storage.type": "SSD" },
  { name: 1, "details.storage.type": 1, _id: 0 }
) 

This query efficiently retrieves the relevant data.