Skip to content

Querying arrays

A document field can hold an array, and querying one has a friendly surprise built in: when you filter an array field against a plain value, MongoDB checks every element and matches if any of them satisfies the condition. That single rule makes simple array queries read exactly like scalar ones. The subtleties show up only when you need several conditions to hold on the same element, which is where $elemMatch earns its keep.

For this lesson each member carries a borrowed array of book titles, and some carry a tags array of interest labels.

To ask “who currently has Compilers checked out?”, filter the array field by the value as if it were scalar. MongoDB looks inside the array for you:

db.members.find({ borrowed: "Compilers" })

Any member whose array contains that title matches, no matter where it sits in the list:

[
{
"_id": "65f0b3d4e4b0a1c2e4b0a1d2",
"name": "Margaret",
"borrowed": ["Algorithms", "Compilers"]
}
]

Several conditions on the same element: $elemMatch

Section titled “Several conditions on the same element: $elemMatch”

Here is the trap. Suppose scores holds an array of numbers and you want documents with an element greater than 80 and less than 90. Writing { scores: { $gt: 80, $lt: 90 } } does not mean that — it matches if some element is over 80 and some (possibly different) element is under 90. To pin both conditions to one element, use $elemMatch:

db.members.find({
scores: { $elemMatch: { $gt: 80, $lt: 90 } }
})

Only documents with a single element in the 81–89 range match — here 85 qualifies, even though the array also holds values outside the band:

[
{ "_id": "65f0b3d4e4b0a1c2e4b0a1d4", "name": "Grace", "scores": [70, 85, 95] }
]

$all matches when the array contains every listed value, in any order. It is the AND of membership. “Who has borrowed both Algorithms and Compilers at once?” is exactly this:

db.members.find({
borrowed: { $all: ["Algorithms", "Compilers"] }
})

Only members holding both titles are returned; having one is not enough:

[
{
"_id": "65f0b3d4e4b0a1c2e4b0a1d2",
"name": "Margaret",
"borrowed": ["Algorithms", "Compilers"]
}
]

$size matches arrays of an exact length. “Who currently has exactly two books out?” is a one-operator query:

db.members.find({ borrowed: { $size: 2 } })

Members whose borrowed array has precisely two elements match:

[
{
"_id": "65f0b3d4e4b0a1c2e4b0a1d2",
"name": "Margaret",
"borrowed": ["Algorithms", "Compilers"]
}
]

Array positions are addressable with a dotted numeric path: borrowed.0 is the first element, borrowed.1 the second, and so on. Use this to query the element at a known position — “whose first borrowed book is Algorithms?”:

db.members.find({ "borrowed.0": "Algorithms" })

The same dot path works when the array holds sub-documents — reviews.0.rating reaches into the first review’s rating field, a pattern the next lesson explores in depth.

In Compass: array filters go in the filter bar just like scalar ones, for example { borrowed: { $size: 2 } }. Compass renders matching arrays inline and lets you expand them to see each element.

  • Why $elemMatch matters: without it, multiple conditions on an array field are checked across all elements, so { scores: { $gt: 80, $lt: 90 } } can match an array like [70, 95] — one element clears each bar separately. $elemMatch forces all conditions onto a single element, which is almost always what you actually meant.
  • $all is order-independent. It only checks that each value is present somewhere; it says nothing about position or about extra elements. $size, by contrast, fixes the exact length.
  • $size takes a literal number only. You cannot write { $size: { $gt: 1 } }. To query “more than one element”, model a length field or use the aggregation framework.
  • A single-value filter on an array matches by containment. { borrowed: "Compilers" } matches any array that contains that title — it does not require the array to equal ["Compilers"].
You filter an array field borrowed against the plain value "Compilers". What matches?
Why use $elemMatch instead of two conditions directly on an array field?
What does { borrowed: { $all: ["Algorithms", "Compilers"] } } match?
How do you match documents whose array has exactly three elements?