0Pricing
MongoDB Academy · درس

‏$elemMatch: مطابقة المستندات الفرعية في المصفوفات

سيستخدم المتعلمون $elemMatch لتطبيق شروط متعددة على عنصر واحد في المصفوفة، وتجنب النتائج الإيجابية الزائفة الناتجة عن المطابقة عبر الحقول الموزعة.

‏$elemMatch: مطابقة المستندات الفرعية في المصفوفات درس مجاني في MongoDB Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في 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) وفتح باقي دورة MongoDB Academy، انتقل إلى CoddyKit PRO. تتضمن دورة MongoDB Academy 4 دروس في المجموع.

ماذا ستتعلم في «‏$elemMatch: مطابقة المستندات الفرعية في المصفوفات»؟

سيستخدم المتعلمون $elemMatch لتطبيق شروط متعددة على عنصر واحد في المصفوفة، وتجنب النتائج الإيجابية الزائفة الناتجة عن المطابقة عبر الحقول الموزعة. تتمرن على MongoDB Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ MongoDB Academy؟

لا تُشترط خبرة سابقة. MongoDB Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «‏$elemMatch: مطابقة المستندات الفرعية في المصفوفات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس MongoDB Academy هذا؟

نعم. كل درس في MongoDB Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الاستعلام عن المصفوفات: $all و$size وElement Match
  2. ‏$elemMatch: مطابقة المستندات الفرعية في المصفوفات
  3. تحديث المصفوفات: $push و$pull و$pop و$addToSet
  4. التحديثات الموضعية والموضعية المفلترة
← العودة إلى MongoDB Academy