$elemMatch: Mencocokkan Subdokumen Array
Peserta didik akan menggunakan $elemMatch untuk menerapkan beberapa kondisi pada satu elemen array, sehingga menghindari hasil positif palsu akibat pencocokan bidang yang tersebar.
$elemMatch: Mencocokkan Subdokumen Array adalah pelajaran MongoDB Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar MongoDB Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus MongoDB Academy mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
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 conditionsUsing 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.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “$elemMatch: Mencocokkan Subdokumen Array” gratis?
Ya — teks lengkap “$elemMatch: Mencocokkan Subdokumen Array” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus MongoDB Academy, upgrade ke CoddyKit PRO. Kursus MongoDB Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “$elemMatch: Mencocokkan Subdokumen Array”?
Peserta didik akan menggunakan $elemMatch untuk menerapkan beberapa kondisi pada satu elemen array, sehingga menghindari hasil positif palsu akibat pencocokan bidang yang tersebar. Kamu berlatih MongoDB Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai MongoDB Academy?
Tidak diperlukan pengalaman sebelumnya. MongoDB Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “$elemMatch: Mencocokkan Subdokumen Array” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran MongoDB Academy ini?
Ya. Setiap pelajaran MongoDB Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Membuat Kueri Array: $all, $size, dan Pencocokan Elemen
- $elemMatch: Mencocokkan Subdokumen Array
- Memperbarui Array: $push, $pull, $pop, $addToSet
- Pembaruan Posisional dan Positional Terfilter