DEV Community

Mohammed Taukir Sheikh
Mohammed Taukir Sheikh

Posted on

Fixing Slow MongoDB Queries on Array Fields Using `$elemMatch`

When working with MongoDB, queries on arrays of objects can sometimes become slow even if you have indexes.

In this article, we’ll explore why that happens and how using $elemMatch can make your queries fast and efficient.


1. The Data Structure

Suppose you have a users collection with documents like this:

{
  name: "Alice",
  cart: [
    { product: "Apple", quantity: 2 },
    { product: "Banana", quantity: 5 }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Here:

  • cart is an array of objects.
  • Each object contains:

    • product → name of the item
    • quantity → how many of that item

2. The Common Query

You want to find users who have 2 Apples in their cart:

{
  "cart.product": "Apple",
  "cart.quantity": 2
}
Enter fullscreen mode Exit fullscreen mode

At first glance, this seems correct.

But MongoDB interprets it as:

Find users where some array element has product = Apple
AND some array element has quantity = 2

⚠️ Notice: MongoDB does not guarantee these two conditions are in the same cart item.


3. Why This Can Be Slow

Consider a user document like this:

{
  name: "Bob",
  cart: [
    { product: "Apple", quantity: 1 },
    { product: "Banana", quantity: 2 }
  ]
}
Enter fullscreen mode Exit fullscreen mode
  • cart.product = Apple → matches first element ✅
  • cart.quantity = 2 → matches second element ✅

MongoDB thinks this document could match.
It must fetch and check the full document, even though there’s no cart item with Apple and quantity 2 together.

This unnecessary document fetch makes queries slow, especially on large collections.


4. The $elemMatch Solution

To fix this, use $elemMatch:

{
  cart: {
    $elemMatch: {
      product: "Apple",
      quantity: 2
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now MongoDB understands:

Find a single element in the cart array where both conditions match.

This allows MongoDB to:

  • Use the index efficiently (if you have one)
  • Avoid scanning unnecessary documents
  • Dramatically improve performance

5. Indexing for Speed

If your collection is large, create a compound index on the array fields:

db.users.createIndex({ "cart.product": 1, "cart.quantity": 1 })
Enter fullscreen mode Exit fullscreen mode

With $elemMatch, MongoDB can directly use this index for the query.


6. Visual Comparison

❌ Without $elemMatch:

MongoDB workflow:

1. Find any element with product = "Apple"
2. Scan each document to check if quantity = 2 exists
3. Return documents
Enter fullscreen mode Exit fullscreen mode
  • Can scan thousands of documents unnecessarily

✅ With $elemMatch:

MongoDB workflow:

1. Find elements with product = "Apple" AND quantity = 2 in the same array item
2. Return matching documents immediately
Enter fullscreen mode Exit fullscreen mode
  • Only fetches the relevant documents
  • Much faster

7. Key Takeaways

  1. When querying multiple conditions on an array of objects, always use $elemMatch.
  2. $elemMatch ensures all conditions match the same array element.
  3. Combine $elemMatch with indexes for maximum performance.
  4. This simple change can make queries up to 100× faster.

Example Summary

// Slow query (can match across different elements)
db.users.find({ "cart.product": "Apple", "cart.quantity": 2 });

// Fast query (matches same element)
db.users.find({
  cart: { $elemMatch: { product: "Apple", quantity: 2 } }
});
Enter fullscreen mode Exit fullscreen mode

Top comments (0)