0Pricing
MongoDB Academy · 강의

$elemMatch: 배열 하위 문서 일치시키기

학습자는 $elemMatch를 사용해 하나의 배열 요소에 여러 조건을 적용하고, 여러 필드에 분산된 일치로 인한 잘못된 양성 결과를 방지합니다.

$elemMatch: 배열 하위 문서 일치시키기은(는) CoddyKit의 무료 MongoDB Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 MongoDB Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

The Sub-Document Array Pattern

It's common in MongoDB to store arrays of embedded sub-documents—objects with multiple fields—inside a parent document. Examples include orders containing line items, users with multiple addresses, or students with per-subject scores. Querying these structures requires care to avoid the spread field problem where conditions are matched across different array elements.

// Example: student with per-subject scores
db.students.insertMany([
  {
    name: 'Alice',
    scores: [
      { subject: 'math', score: 95, grade: 'A' },
      { subject: 'english', score: 72, grade: 'C' }
    ]
  },
  {
    name: 'Bob',
    scores: [
      { subject: 'math', score: 68, grade: 'D' },
      { subject: 'english', score: 91, grade: 'A' }
    ]
  }
]);

The Spread Field Problem Revisited

When you filter an array of sub-documents using dot-notation fields directly, MongoDB applies each condition independently to any element in the array. The query { 'scores.subject': 'math', 'scores.grade': 'A' } would match a document if any element has subject='math' AND any (possibly different) element has grade='A'. This false-positive behavior is the spread field problem.

// Problematic query - spread field issue
db.students.find({
  'scores.subject': 'math',
  'scores.grade': 'A'
});
// Returns BOTH Alice AND Bob!
// Alice: scores[0] has subject='math', scores[0] has grade='A' -> correct match
// Bob:   scores[0] has subject='math' + scores[1] has grade='A' -> false positive!

$elemMatch Fixes the Spread Problem

$elemMatch is the solution: it constrains all conditions to match on the same single array element. MongoDB only returns a document if at least one element in the array satisfies every condition inside the $elemMatch block simultaneously. This is the correct way to query arrays of sub-documents with multiple conditions.

// Correct query with $elemMatch
db.students.find({
  scores: {
    $elemMatch: {
      subject: 'math',
      grade: 'A'
    }
  }
});
// Returns ONLY Alice (scores[0] has BOTH subject='math' AND grade='A')
// Bob is excluded: no single element satisfies both conditions

Using Range Operators Inside $elemMatch

You can use any MongoDB query operator inside $elemMatch, including range operators like $gt, $lte, and $in. This lets you express conditions like 'find any element where score is between 80 and 100 AND the subject is math'—conditions that must be true for one specific element.

// Find students with a math score above 80
db.students.find({
  scores: {
    $elemMatch: {
      subject: 'math',
      score: { $gt: 80 }
    }
  }
});
// Returns Alice (math score is 95 > 80)

// With $in inside $elemMatch
db.students.find({
  scores: {
    $elemMatch: {
      subject: { $in: ['math', 'science'] },
      grade: 'A'
    }
  }
});

Negating $elemMatch Results

You can negate an $elemMatch condition using $not to find documents where no array element satisfies all the conditions. For example, 'find students who do NOT have a math A' means 'no element satisfies both subject=math AND grade=A'. This is more precise than checking { 'scores.grade': { $ne: 'A' } } which would exclude students with any A-grade subject.

// Students who do NOT have a math A
db.students.find({
  scores: {
    $not: {
      $elemMatch: {
        subject: 'math',
        grade: 'A'
      }
    }
  }
});
// Returns Bob (his math score is D, not A)

$elemMatch in Projection

$elemMatch can also be used in the projection (second argument to find()) to return only the first array element that matches a condition. When used in projection, it's called the $elemMatch projection operator (same name, different context). It returns at most one matching element per document.

// Project only the FIRST matching scores element
db.students.find(
  { name: 'Alice' },
  {
    name: 1,
    scores: {
      $elemMatch: { subject: 'math' }
    }
  }
);
// Returns:
// { name: 'Alice', scores: [{ subject: 'math', score: 95, grade: 'A' }] }
// Only the math element is included, english is excluded

$elemMatch Projection vs $ Positional

There are two ways to project a single matching array element: the $elemMatch projection (in the projection object) lets you specify a different filter than the query filter, while the positional $ operator returns the first element matched by the query filter itself. Use $elemMatch in projection when the query filter and the element you want to project are different.

// $ positional: returns the element matched by the query filter
db.students.find(
  { 'scores.subject': 'math' },
  { 'scores.$': 1 }
);

// $elemMatch projection: different filter from query
db.students.find(
  { name: 'Alice' },  // query doesn't filter scores
  { scores: { $elemMatch: { grade: 'A' } } }  // but project only A-grade scores
);

Deeply Nested Array Sub-Documents

MongoDB supports querying arrays of arrays and deeply nested sub-documents using chained dot notation. However, $elemMatch only applies at one level deep at a time. For queries on arrays nested inside arrays, you need to chain multiple $elemMatch operators or restructure your schema to avoid excessive nesting.

// Document with nested arrays
// { courses: [{ name: 'Math', lessons: [{ id: 1, score: 95 }] }] }

// Query nested array with chained dot notation
db.curriculum.find({ 'courses.lessons.score': { $gt: 90 } });

// More precise with $elemMatch (one level)
db.curriculum.find({
  courses: {
    $elemMatch: {
      name: 'Math',
      'lessons.score': { $gt: 90 }  // dot notation within $elemMatch
    }
  }
});

Indexing for $elemMatch Queries

A multikey index on the array field supports $elemMatch queries. MongoDB uses the index to narrow down candidate documents by the indexed field values, then applies the full $elemMatch condition to confirm each candidate. To maximise index efficiency, include the most selective field of your $elemMatch condition in the index.

// Index on scores.subject for efficient $elemMatch queries
db.students.createIndex({ 'scores.subject': 1 });

// This $elemMatch query can use the index to find 'math' entries,
// then applies the grade: 'A' condition on those candidates
db.students.find({
  scores: {
    $elemMatch: {
      subject: 'math',  // <-- indexed, drives the IXSCAN
      grade: 'A'        // <-- applied after index lookup
    }
  }
});

$elemMatch With $exists and $type

You can use $exists and $type inside $elemMatch to find array elements that have optional fields or match a specific BSON type. This is useful for heterogeneous arrays where not all elements share the same shape—common in legacy data migrations or flexible event log schemas.

// Find docs with at least one scores element that has a 'notes' field
db.students.find({
  scores: {
    $elemMatch: {
      notes: { $exists: true }
    }
  }
});

// Find docs with a scores element where score is a string (data quality check)
db.students.find({
  scores: {
    $elemMatch: {
      score: { $type: 'string' }  // should be a number!
    }
  }
});

Real-World Example: E-Commerce Orders

A practical use of $elemMatch is in e-commerce: finding orders that contain a line item for a specific product with a quantity above a threshold. Without $elemMatch, the conditions would spread across different line items and produce false positives.

// Find orders containing 'product-123' with qty > 5
db.orders.find({
  lineItems: {
    $elemMatch: {
      productId: 'product-123',
      qty: { $gt: 5 }
    }
  }
});

// Also useful for status-filtered sub-documents:
db.projects.find({
  tasks: {
    $elemMatch: {
      assignee: 'alice',
      status: 'in-progress',
      priority: { $gte: 3 }
    }
  }
});

Quick Check

Test your understanding of $elemMatch for matching array sub-documents.

Lesson Recap

In this lesson you learned: $elemMatch in queries requires all conditions to match a single array element, solving the spread field problem, $elemMatch in projection returns only the first matching element, and multikey indexes support $elemMatch queries efficiently. Next up we tackle array update operators.

자주 묻는 질문

“$elemMatch: 배열 하위 문서 일치시키기” 강의는 무료인가요?

네 — “$elemMatch: 배열 하위 문서 일치시키기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 MongoDB Academy 강의 전체를 잠금 해제할 수 있습니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“$elemMatch: 배열 하위 문서 일치시키기”에서 뭘 배우나요?

학습자는 $elemMatch를 사용해 하나의 배열 요소에 여러 조건을 적용하고, 여러 필드에 분산된 일치로 인한 잘못된 양성 결과를 방지합니다. 브라우저에서 직접 실행하는 실습 코드로 MongoDB Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

MongoDB Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 MongoDB Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“$elemMatch: 배열 하위 문서 일치시키기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 MongoDB Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 MongoDB Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 배열 쿼리하기: $all, $size, 요소 일치
  2. $elemMatch: 배열 하위 문서 일치시키기
  3. 배열 업데이트하기: $push, $pull, $pop, $addToSet
  4. 위치 지정 및 필터링된 위치 지정 업데이트
← MongoDB Academy(으)로 돌아가기