MongoDB Academy · Lektion

$elemMatch: matcha underdokument i arrayer

Ni använder $elemMatch för att tillämpa flera villkor på ett enda arrayelement och undviker falska positiva resultat från matchning över flera fält.

Lektion 2 av 413 steg

$elemMatch: matcha underdokument i arrayer är en gratis lektion i MongoDB Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för MongoDB Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Mönstret med arrayen av underdokument

Det är vanligt i MongoDB att lagra arrayer med inbäddade underdokument – objekt med flera fält – i ett överordnat dokument. Exempel är order som innehåller orderrader, användare med flera adresser eller studenter med poäng per ämne. Det krävs omsorg vid frågor mot dessa strukturer för att undvika problemet med spridda fält, där villkor matchas över olika arrayelement.

// 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' }
    ]
  }
]);

Problemet med spridda fält – igen

När Ni filtrerar en array med underdokument genom att direkt använda fält med punktnotation, tillämpar MongoDB varje villkor oberoende på valfritt element i arrayen. Frågan { 'scores.subject': 'math', 'scores.grade': 'A' } skulle matcha ett dokument om något element har subject='math' OCH något (eventuellt ett annat) element har grade='A'. Detta beteende, som ger falska positiva träffar, är problemet med spridda fält.

// 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 löser problemet med spridda fält

$elemMatch är lösningen: den begränsar alla villkor så att de matchar samma enskilda arrayelement. MongoDB returnerar endast ett dokument om minst ett element i arrayen samtidigt uppfyller alla villkor i blocket $elemMatch. Detta är det korrekta sättet att fråga efter arrayer med underdokument och flera villkor.

// 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

Använda intervalloperatorer inuti $elemMatch

Ni kan använda vilken MongoDB-frågeoperator som helst inuti $elemMatch, inklusive intervalloperatorer som $gt, $lte och $in. Det gör att Ni kan uttrycka villkor som ”hitta ett element där poängen ligger mellan 80 och 100 OCH ämnet är matematik” – villkor som måste vara sanna för ett specifikt 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'
    }
  }
});

Negera resultat från $elemMatch

Ni kan negera ett $elemMatch-villkor med $not för att hitta dokument där inget arrayelement uppfyller alla villkor. Exempelvis betyder ”hitta studenter som INTE har ett A i matematik” att ”inget element uppfyller både subject=math och grade=A”. Detta är mer precist än att kontrollera { 'scores.grade': { $ne: 'A' } }, vilket skulle utesluta studenter som har ett A i något ämne.

// 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 i projektion

$elemMatch kan även användas i projektionen (det andra argumentet till find()) för att endast returnera det första arrayelementet som matchar ett villkor. När den används i en projektion kallas den projektionsoperatorn $elemMatch (samma namn, men ett annat sammanhang). Den returnerar högst ett matchande element per dokument.

// 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-projektion jämfört med positionella $

Det finns två sätt att projicera ett enskilt matchande arrayelement: $elemMatch-projektionen (i projektionsobjektet) låter Er ange ett annat filter än frågefiltret, medan den positionella $-operatorn returnerar det första element som matchades av själva frågefiltret. Använd $elemMatch i projektionen när frågefiltret och elementet Ni vill projicera skiljer sig åt.

// $ 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
);

Djupt nästlade underdokument i arrayer

MongoDB stöder frågor mot arrayer av arrayer och djupt nästlade underdokument med kedjad punktnotation. $elemMatch tillämpas dock endast på en nivå åt gången. För frågor mot arrayer som är nästlade i arrayer behöver Ni kedja flera $elemMatch-operatorer eller strukturera om schemat för att undvika överdriven nästling.

// 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
    }
  }
});

Indexering för $elemMatch-frågor

Ett multikey-index på arrayfältet stöder $elemMatch-frågor. MongoDB använder indexet för att begränsa kandidatdokumenten utifrån de indexerade fältvärdena och tillämpar sedan hela $elemMatch-villkoret för att bekräfta varje kandidat. För att maximera indexets effektivitet bör Ni inkludera det mest selektiva fältet i Ert $elemMatch-villkor i indexet.

// 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 med $exists och $type

Ni kan använda $exists och $type inuti $elemMatch för att hitta arrayelement som har valfria fält eller motsvarar en specifik BSON-typ. Detta är användbart för heterogena arrayer där inte alla element har samma struktur – något som är vanligt vid migrering av äldre data eller i flexibla scheman för händelseloggar.

// 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!
    }
  }
});

Praktiskt exempel: e-handelsorder

Ett praktiskt användningsområde för $elemMatch är e-handel: att hitta order som innehåller en orderrad för en specifik produkt med en kvantitet över ett tröskelvärde. Utan $elemMatch skulle villkoren spridas över olika orderrader och ge falska positiva träffar.

// 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 }
    }
  }
});

Snabb kontroll

Testa Er förståelse av $elemMatch för matchning av arrayens underdokument.

Sammanfattning av lektionen

I den här lektionen har Ni lärt Er att $elemMatch i frågor kräver att alla villkor matchar ett enda arrayelement, vilket löser problemet med spridda fält, att $elemMatch i projektion endast returnerar det första matchande elementet och att multikey-index stöder $elemMatch-frågor effektivt. Nästa steg är arrayoperatorer för uppdatering.

Gratis att börja

Lär dig JavaScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”$elemMatch: matcha underdokument i arrayer” gratis?

Ja – hela texten till ”$elemMatch: matcha underdokument i arrayer” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i MongoDB Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i MongoDB Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”$elemMatch: matcha underdokument i arrayer”?

Ni använder $elemMatch för att tillämpa flera villkor på ett enda arrayelement och undviker falska positiva resultat från matchning över flera fält. Ni övar på MongoDB Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig MongoDB Academy?

Du behöver inga förkunskaper. Utbildningen i MongoDB Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”$elemMatch: matcha underdokument i arrayer”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här MongoDB Academy-lektionen?

Ja. Varje MongoDB Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Fråga efter arrayer: $all, $size och elementmatchning
  2. $elemMatch: matcha underdokument i arrayer
  3. Uppdatera arrayer: $push, $pull, $pop och $addToSet
  4. Positionella och filtrerade positionella uppdateringar
← Tillbaka till MongoDB Academy