MongoDB: استعلامات المصفوفات والوثائق المتداخلة
آخر تحديث: 2026-08-26
تعد المستندات والمصفوفات المتداخلة من الميزات الأساسية في MongoDB — لذا عليك إتقانها للاستفادة القصوى من نموذج المستندات.
تقدم هذه الدورة نظرة متعمقة على استعلامات المصفوفات، وترميز نقاط المستندات المتداخلة، والمطابقة التامة باستخدام $elemMatch، وعمليات تحديث المصفوفات.
1. ما ستتعلمه
- الاستعلام عن المستندات المتداخلة باستخدام تدوين النقطة
- استعلامات حقول المصفوفات (عنصر واحد، عناصر متعددة)
- $elemMatch: مطابقة تامة لعنصر في نفس المصفوفة
$تحديث العنصر النائب للموقع- فهرس المصفوفة (فهرس متعدد المفاتيح)
- المفاضلات التصميمية بين المصفوفات والمراجع
2. القصة الحقيقية لمهندس بيانات في مجال التجارة الإلكترونية
(1) المشكلة: الاستعلامات على المستندات المتداخلة تُرجع نتائج غير صحيحة
كانت أليس تعمل على صيانة نظام مراجعة المنتجات عندما واجهت خطأً في الاستعلام:
// ❌ Counterexample:Search"Rating >= 4 and includes 'good' Keywords"Comments on
db.products.find({
"reviews.rating": { $gte: 4 },
"reviews.content": /good/i
});
// ⚠️ Question:May match different comments(One comment, high rating,Another one containing good)
// Expectations:A comment meets both conditions at the same time
(2) حل للمطابقة التامة باستخدام $elemMatch
// ✅ Correct Example:Use $elemMatch
db.products.find({
reviews: {
$elemMatch: {
rating: { $gte: 4 },
content: /good/i
}
}
});
// ✅ Correct:A single comment that meets all of the following criteria
graph TB
subgraph "Embedded Documentation"
A1[products Gathering] --> A2[Document 1<br/>address: {<br/> city: Tokyo<br/> country: Japan<br/>}]
end
subgraph "Citation-Style Documentation"
B1[products Gathering] --> B2[Document 1<br/>addressId: ObjectId]
B3[addresses Gathering] --> B4[Document 1<br/>city: Tokyo]
B2 -.->|Search| B3
end
style A2 fill:#d4edda
3. ترميز عقد المستندات المتداخلة
شرح المفهوم: يُقصد بالمستند المُضمَّن المستند الذي يحتوي على مستند آخر كقيمة لحقل ما. تدعم MongoDB ما يصل إلى 100 مستوى من التداخل؛ ومع ذلك، يُنصح في بيئات الإنتاج بعدم تجاوز 3 مستويات. الترميز بالنقطة هو طريقة للوصول إلى الحقول المتداخلة باستخدام صيغة "field.subfield.subsubfield"، وهو الآلية الأساسية للاستعلام عن البيانات المتداخلة وتحديثها في MongoDB.
كيفية العمل: عندما يقوم MongoDB بتحليل الترميز النقطي، فإنه يحدد مسارات الحقول طبقةً تلو الأخرى من المستويات الخارجية إلى الداخلية. يقوم محرك الاستعلام بتقسيم "specs.screen.size" إلى doc.specs.screen.size ويتنقل عبر شجرة مستند BSON مستوىً تلو الآخر. كما تدعم الفهارس الحقول المكتوبة بالترميز النقطي؛ على سبيل المثال، يمكن استخدام { "specs.screen.size": 1 } لإنشاء فهارس فعالة.
graph TD
A[BSON Document] --> B[specs: Object]
B --> C[screen: Object]
C --> D["size: '6.5'"]
C --> E["type: 'OLED'"]
B --> F[battery: Object]
F --> G["capacity: '4500mAh'"]
H["specs.screen.size"] -->|Analysis of Dot Notation| D
I["specs.battery.capacity"] -->|Analysis of Dot Notation| G
style D fill:#d4edda
style G fill:#d4edda
| البعد | الوصف |
|---|---|
| السيناريوهات التي ينطبق عليها | البيانات ذات التسلسل الهرمي الثابت التي تُقرأ وتُكتب معًا (مثل العناوين والمواصفات) |
| الحالات التي لا ينطبق عليها ذلك | البيانات ذات التسلسل الهرمي غير المؤكد أو التي يتم تحديثها بشكل متكرر وبشكل مستقل (استخدم المراجع) |
| التأثير على الأداء | مستوى واحد ≈ حقل عادي؛ المستويات المتعددة تتطلب عملية اجتياز — يُوصى بألا يتجاوز عدد المستويات 3 مستويات |
| دعم الفهرس | مدعوم بالكامل؛ { "a.b.c": 1 } يعادل الفهرس العادي |
(1) الاستعلام عن المستندات المتداخلة وتحديثها
// === Nested Document Structure ===
db.products.insertOne({
sku: 'PHONE-001',
title: 'Smartphone X',
specs: {
screen: { size: '6.5', type: 'OLED' },
battery: { capacity: '4500mAh', type: 'Li-Po' }
}
});
// === Dot Notation Query ===
db.products.find({ "specs.screen.size": '6.5' });
// === Multi-level nesting ===
db.products.find({ "specs.battery.capacity": '4500mAh' });
// === Updating Nested Fields ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $set: { "specs.battery.capacity": "5000mAh" } }
);
4. استعلامات حقول المصفوفات
شرح المفهوم: تعد المصفوفات من أكثر هياكل البيانات مرونة في نموذج المستندات في MongoDB. يمكن لحقل واحد تخزين قيم متعددة، وتتبع استعلامات MongoDB على حقول المصفوفات مبدأ «التطابق الجزئي» — فما دام عنصر واحد في المصفوفة يستوفي الشرط، يتم اختيار المستند. وهذا يجعل استعلامات المصفوفات قوية في الوقت نفسه عرضة لنتائج غير متوقعة.
كيفية العمل: يستخدم محرك الاستعلام في MongoDB استراتيجية «المطابقة بالتوسيع الضمني» لحقول المصفوفات. عند إجراء استعلام عن { tags: '5g' }، يتحقق المحرك من عناصر المصفوفة واحدة تلو الأخرى؛ فإذا كان أي عنصر يساوي '5g'، يُعتبر ذلك مطابقة. بالنسبة للاستعلامات متعددة الشروط (مثل {"reviews.rating": {$gte:4}, "reviews.content": /good/})، تتطابق كل شرط مع عناصر المصفوفة بشكل مستقل، مما قد يؤدي إلى تطابق عناصر مختلفة — وهذا هو سبب وجود $elemMatch.
graph LR
A[Query Criteria] --> B{Array Matching Strategies}
B -->|Single condition| C[Any element matches<br/>tags: '5g']
B -->|Multi-condition point notation| D[Independent matching of each condition<br/>May hit different elements]
B -->|Multiple conditions $elemMatch| E[The same element must<br/>Meets all conditions at the same time]
C --> F[✅ Simple and Efficient]
D --> G[⚠️ May not be accurate]
E --> H[✅ Exact Match]
style F fill:#d4edda
style G fill:#fff3cd
style H fill:#d4edda
| طريقة البحث | قواعد المطابقة | السيناريوهات القابلة للتطبيق |
|---|---|---|
{ tags: '5g' } |
أي عنصر يساوي «5g» | مطابقة لقيمة واحدة |
{ tags: { $all: ['5g','amoled'] } } |
يجب تضمين جميع القيم | قيم متعددة |
{ tags: { $in: ['5g','fast'] } } |
يحتوي على أي قيمة | قيم متعددة أو مطابقات |
{ "tags.0": '5g' } |
تحديد موضع الفهرس | مطابقة الموضع |
{ tags: { $size: 3 } } |
المطابقة التامة لطول المصفوفة | مرشح الطول |
(1) مطابقة عنصر واحد
// === An array contains the specified elements ===
db.products.find({ tags: '5g' });
// tags The array contains '5g' All Products
// === The array contains all the specified elements($all)===
db.products.find({ tags: { $all: ['5g', 'amoled'] } });
// Must include both '5g' and 'amoled'
// === The array contains any element($in)===
db.products.find({ tags: { $in: ['5g', 'fast-charging'] } });
// Includes '5g' or 'fast-charging'
(2) الاستعلام عن عناصر المصفوفة باستخدام الرقم الترتيبي
// === Get the first element of an array ===
db.products.find({ "tags.0": '5g' });
// tags[0] = '5g'
// === Retrieve the second element of the array ===
db.products.find({ "tags.1": 'amoled' });
// tags[1] = 'amoled'
// === Querying the Range of Array Elements ===
db.products.find({ "tags.0": { $in: ['new', 'sale'] } });
(3) التحقق من طول المصفوفة
// === Exact Match for Array Length ===
db.products.find({ tags: { $size: 3 } });
// Number of tags = 3
// === Query on Array Length Range ===
db.products.find({
$expr: { $gt: [{ $size: '$tags' }, 3] }
});
// Number of tags > 3
5. $elemMatch: المطابقة التامة
شرح المفهوم: $elemMatch هو عامل مطابقة تامة مصمم خصيصًا لحقول المصفوفات في MongoDB. وهو يضمن أن نفس عنصر المصفوفة يستوفي جميع شروط الاستعلام في آن واحد، بدلاً من أن يستوفي كل عنصر من العناصر المختلفة بعض الشروط فقط. وعندما تكون عناصر المصفوفة كائنات (مثل التعليقات أو الدرجات) ويكون الاستعلام الذي يتطلب ربطًا متعدد الحقول ضروريًا، فإن $elemMatch هو الخيار الصحيح الوحيد.
كيفية العمل: $elemMatch يطبق جميع الشروط على كل عنصر في المصفوفة واحدًا تلو الآخر. ولا يُعتبر العنصر مطابقًا إلا إذا اجتاز جميع اختبارات الشروط في آن واحد. الفرق الرئيسي عن الترميز بالنقطة: في الترميز بالنقطة، تقوم الشروط المتعددة بمسح المصفوفة وقد تتطابق مع عناصر مختلفة؛ أما $elemMatch فيتطلب أن يجتاز عنصر واحد جميع الاختبارات.
sequenceDiagram
participant Query as Search Engine
participant Doc as Document<br/>reviews: [{rating:5,content:"bad"},<br/>{rating:3,content:"good"}]
Note over Query,Doc: Dot Notation Query: reviews.rating>=4 AND reviews.content=/good/
Query->>Doc: Conditions1: rating>=4 → Hit Element0
Query->>Doc: Conditions2: /good/ → Hit Element1
Doc-->>Query: ⚠️ Different elements each meet some of the conditions → Return to this document
Note over Query,Doc: $elemMatch Search
Query->>Doc: Element0: rating>=4 ✅, /good/ ❌ → Mismatch
Query->>Doc: Element1: rating>=4 ❌ → Mismatch
Doc-->>Query: ✅ No elements satisfy all of the following conditions → Does not return
| بُعد المقارنة | تدوين النقاط | $elemMatch |
|---|---|---|
| دقة المطابقة | تتم مطابقة كل شرط على حدة | يجب استيفاء جميع الشروط الخاصة بالعنصر نفسه |
| الصيغة | { "a.b": x, "a.c": y } |
{ a: { $elemMatch: { b: x, c: y } } } |
| الدقة | ⚠️ قد تستهدف عناصر مختلفة | ✅ دقيقة حتى مستوى العنصر الواحد |
| الأداء | أسرع قليلاً (يمكن استخدام الفهارس بشكل منفصل) | أبطأ قليلاً (يتطلب فحص كل عنصر) |
| دعم الفهارس | يمكن معالجة شروط متعددة بشكل منفصل عبر الفهارس | يلزم وجود فهرس مركب |
(1) القضية الأساسية
// === Counterexample:Matching Elements in Different Arrays ===
db.products.find({
"reviews.rating": { $gte: 4 },
"reviews.content": /good/i
});
// Possible matches:review1.rating=5, review2.content="good"
// That is, different comments each satisfy the condition
// ✅ Correct Example:$elemMatch Match the same element
db.products.find({
reviews: {
$elemMatch: {
rating: { $gte: 4 },
content: /good/i
}
}
});
// A single comment must meet all of the following criteria at the same time
(2) الحالات المعقدة
// === Multiple conditions elemMatch ===
db.products.find({
reviews: {
$elemMatch: {
rating: { $gte: 4 },
helpful: { $gt: 10 },
createdAt: { $gte: new Date('2026-01-01') }
}
}
});
// === Nested elemMatch ===
db.students.find({
courses: {
$elemMatch: {
name: 'Math',
score: { $gte: 90 },
assignments: {
$elemMatch: {
submitted: true,
grade: { $gte: 80 }
}
}
}
}
});
6. مُعدِّلات تحديث المصفوفات
شرح المفهوم: توفر MongoDB مجموعة من مُعدِّلات التحديث المخصصة خصيصًا لمعالجة حقول المصفوفات: $push (إلحاق)، $pull (حذف)، $addToSet (إلحاق دون تكرار)، $pop (إزالة العنصر الأول والأخير). عند استخدامها بالاقتران مع العنصر النائب للموضع $ وarrayFilters، تتيح لك هذه العوامل تحديث عناصر محددة في المصفوفة بدقة دون استبدال المصفوفة بأكملها.
كيفية العمل: يتم تنفيذ مُعدِّلات تحديث المصفوفات بشكل متكامل على خادم MongoDB. $push يُضيف عنصرًا إلى نهاية المصفوفة؛ $addToSet يتحقق من وجود العنصر بالفعل قبل إضافته؛ $pull يُضيف عنصرًا إلى نهاية المصفوفة؛ $addToSet يتحقق من وجود العنصر قبل إضافته؛ $pull يحذف عنصرًا بناءً على شرط معين؛ $ يشير العنصر النائب إلى موضع أول عنصر في المصفوفة يطابق شرط الاستعلام؛ $[] يشير إلى جميع العناصر؛ $[filter] يعمل بالاقتران مع arrayFilters لإجراء التحديثات الشرطية.
graph TB
A[Array Update Modifiers] --> B[$push<br/>Additional Elements]
A --> C[$pull<br/>Conditional Deletion]
A --> D[$addToSet<br/>Remove Duplicates and Append]
A --> E[$pop<br/>Remove the first and last characters]
F[Position Operators] --> G[$<br/>Update the first match]
F --> H[$[]<br/>Update All Elements]
F --> I[$[filter]<br/>Conditional Batch Update<br/>In conjunction witharrayFilters]
style B fill:#d4edda
style C fill:#f8d7da
style D fill:#cce5ff
style I fill:#fff3cd
| المُعدِّل | الوظيفة | مثال |
|---|---|---|
$push |
إضافة عنصر (قابل للتكرار) | { $push: { tags: 'new' } } |
$each |
استخدم $push لإضافة عدة عناصر | { $push: { tags: { $each: ['a','b'] } } } |
$addToSet |
إزالة التكرارات والإضافة | { $addToSet: { tags: 'new' } } |
$pull |
الحذف حسب المعايير | { $pull: { tags: 'old' } } |
$pop |
حذف الأول/الأخير | { $pop: { tags: 1 } } (حذف الأخير) |
$ |
تحديث العنصر الأول المطابق | { $set: { "reviews.$.flagged": true } } |
$[] |
تحديث جميع العناصر | { $set: { "reviews.$[].status": "ok" } } |
$[f] |
التحديث الدفعي المشروط | { arrayFilters: [{ "f.rating": {$lt:2} }] } |
(1) $push: إضافة عنصر
// === Add a single item ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $push: { tags: 'bestseller' } }
);
// === Add multiple($each)===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $push: { tags: { $each: ['5g', 'amoled', 'fast-charging'] } } }
);
(2) $pull: يحذف عنصرًا
// === Delete a Specified Value ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $pull: { tags: 'old-tag' } }
);
// === Delete Multiple ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $pull: { tags: { $in: ['outdated1', 'outdated2'] } } }
);
// === Delete elements that meet the criteria ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $pull: { reviews: { rating: { $lt: 2 } } } }
);
// Delete Rating < 2 Comments on
(3) $ العنصر النائب للموضع
// === Update the first matching array element ===
db.products.updateOne(
{ sku: 'PHONE-001', "reviews.userId": 'user_001' },
{ $set: { "reviews.$.helpful": 10 } }
);
// Update user_001 Comments on
// === Update all matching array elements ===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $set: { "reviews.$[].status": "approved" } }
);
// === Conditional Update(arrayFilters)===
db.products.updateOne(
{ sku: 'PHONE-001' },
{ $set: { "reviews.$[lowRating].flagged": true } },
{ arrayFilters: [{ "lowRating.rating": { $lt: 2 } }] }
);
7. الفهرس متعدد المفاتيح: فهرسة المصفوفات
شرح المفهوم: عندما يكون حقل الفهرس عبارة عن مصفوفة، يقوم MongoDB تلقائيًا بإنشاء فهرس متعدد المفاتيح. وتتمثل الميزة الرئيسية لهذا الفهرس في أن كل عنصر في المصفوفة يُنشئ مفتاح فهرس منفصل. على سبيل المثال، سيؤدي tags: ['5g', 'amoled'] إلى إنشاء مدخلين في الفهرس، يشير كل منهما إلى نفس المستند. وهذا يضمن أن يكون أداء الاستعلامات الخاصة بحقول المصفوفات مكافئًا لأداء الاستعلامات الخاصة بفهارس الحقول العادية.
كيفية العمل: عند إدراج مستند، يتحقق MongoDB مما إذا كان الحقل المفهرس عبارة عن مصفوفة. إذا كان الأمر كذلك، فإنه ينشئ إدخالاً في الفهرس لكل عنصر. وأثناء إجراء الاستعلام، يستخدم MongoDB الفهارس متعددة المفاتيح لتحديد موقع المستند الذي يحتوي على العنصر المستهدف بسرعة. القيد: يمكن أن يحتوي الفهرس المركب على حقل مصفوفة واحد على الأكثر؛ وإلا فإن عدد إدخالات الفهرس سيزداد بشكل هائل (الضرب الديكارتي).
graph LR
A[Document<br/>tags: 5g, amoled, fast] --> B[multikey index]
B --> C["Index Entries: '5g' → docId"]
B --> D["Index Entries: 'amoled' → docId"]
B --> E["Index Entries: 'fast' → docId"]
F["Search {tags: '5g'}"] -->|Index Lookup| C
C --> G[✅ Document in Chinese]
style B fill:#d4edda
style G fill:#d4edda
| قيود المفاتيح المتعددة | الوصف |
|---|---|
| كل عنصر في المصفوفة له مؤشر | يؤثر طول المصفوفة على حجم المؤشر |
| يمكن أن تحتوي الفهارس المركبة على حقل صفيف واحد على الأكثر | منع تضخم الفهرس |
| أداء عالٍ في استعلامات فهرس المصفوفات | تعادل الفهارس العادية للحقول |
| يتعذر فهرسة المصفوفة بأكملها | قم بفهرسة العناصر فقط، وليس المصفوفة نفسها |
▶ المثال 1: دليل عملي للاستعلام عن المستندات المتداخلة
// Scene:ShopHub Checking Product Specifications on E-commerce Platforms
db.products.insertOne({
sku: 'PHONE-002',
title: 'Smartphone Y',
specs: {
screen: { size: '6.7', type: 'AMOLED', refreshRate: '120Hz' },
battery: { capacity: '5000mAh', type: 'Li-Po', fastCharging: true },
storage: { ram: '12GB', internal: '256GB' }
}
});
// Search:AMOLED Products on the Screen
db.products.find({ "specs.screen.type": 'AMOLED' });
// Search:Supports fast charging and has a battery ≥ 5000mAh Products
db.products.find({
"specs.battery.fastCharging": true,
"specs.battery.capacity": { $in: ['5000mAh', '6000mAh'] }
});
// Update:Add Screen Protector Information
db.products.updateOne(
{ sku: 'PHONE-002' },
{ $set: { "specs.screen.protection": "Gorilla Glass 5" } }
);
الإخراج:
TEXT 📖 للعرض فقط{ acknowledged: true, insertedId: ObjectId('...') } [ { _id: ObjectId('...'), sku: 'PHONE-002', title: 'Smartphone Y', specs: { screen: { type: 'AMOLED' } } } ] [ { _id: ObjectId('...'), sku: 'PHONE-002', specs: { battery: { capacity: '5000mAh', fastCharging: true } } } ] { acknowledged: true, matchedCount: 1, modifiedCount: 1 }
النتيجة: تستهدف صيغة النقطة الحقول المتداخلة متعددة المستويات بدقة؛ ولا تؤثر الاستعلامات وعمليات التحديث إلا على الحقول المستهدفة ولا تحل محل الكائن المتداخل بأكمله.
▶ المثال 2: تطبيق عملي شامل لـ $elemMatch وتحديثات المصفوفات
// Scene:ShopHub Product Review Management
db.products.insertOne({
sku: 'LAPTOP-001',
title: 'Laptop Pro',
reviews: [
{ userId: 'user_010', rating: 2, content: 'Poor quality', helpful: 0, createdAt: new Date('2026-05-01') },
{ userId: 'user_011', rating: 5, content: 'Excellent good value', helpful: 30, createdAt: new Date('2026-06-01') },
{ userId: 'user_012', rating: 4, content: 'Good performance', helpful: 12, createdAt: new Date('2026-07-01') }
]
});
// 1. Exact Search:The Same Comment rating>=4 and includes 'good'
db.products.find({
reviews: { $elemMatch: { rating: { $gte: 4 }, content: /good/i } }
});
// Hit only user_011 Comments on(rating=5 and includes "good")
// 2. Use $ to update the first top-rated review
db.products.updateOne(
{ sku: 'LAPTOP-001', "reviews.rating": { $gte: 5 } },
{ $set: { "reviews.$.featured": true } }
);
// 3. Use arrayFilters Mark all low-rated reviews
db.products.updateOne(
{ sku: 'LAPTOP-001' },
{ $set: { "reviews.$[low].flagged": true } },
{ arrayFilters: [{ "low.rating": { $lt: 3 } }] }
);
// 4. Delete all low-rated reviews
db.products.updateOne(
{ sku: 'LAPTOP-001' },
{ $pull: { reviews: { rating: { $lt: 3 } } } }
);
الإخراج:
TEXT 📖 للعرض فقط{ acknowledged: true, insertedId: ObjectId('...') } [ { _id: ObjectId('...'), sku: 'LAPTOP-001', reviews: [{ userId: 'user_011', rating: 5, content: 'Excellent good value', helpful: 30 }] } ] { acknowledged: true, matchedCount: 1, modifiedCount: 1 } { acknowledged: true, matchedCount: 1, modifiedCount: 1 } { acknowledged: true, matchedCount: 1, modifiedCount: 1 }
النتيجة: تتطابق $elemMatch تمامًا مع التعليق نفسه؛
$يقوم بتحديث أول نتيجة مطابقة؛arrayFiltersيقوم بإجراء تحديث جماعي بناءً على الشروط؛$pullيحذف التعليقات التي تستوفي الشروط.
// === Creating an Array Field Index ===
db.products.createIndex({ tags: 1 });
// Automatically become multikey index
// === Composite multikey index ===
db.products.createIndex({ category: 1, tags: 1 });
// === View Index ===
db.products.getIndexes();
▶ المثال 3: تمرين عملي شامل يجمع بين المصفوفات والوثائق المتداخلة
// Complete Scene:Nested Queries for E-commerce Product Reviews
// 1. Preparing the Data:Products with nested reviews
db.products.insertOne({
sku: 'PHONE-001',
title: 'Smartphone X',
specs: {
screen: { size: '6.5', type: 'OLED' },
battery: { capacity: '4500mAh', type: 'Li-Po' }
},
reviews: [
{ userId: 'user_001', rating: 5, content: 'Excellent phone! Great battery', helpful: 15, createdAt: new Date('2026-06-01') },
{ userId: 'user_002', rating: 3, content: 'Good but expensive', helpful: 5, createdAt: new Date('2026-06-15') },
{ userId: 'user_003', rating: 5, content: 'Best phone ever, amazing good quality', helpful: 25, createdAt: new Date('2026-07-01') }
]
});
// 2. Search:Rating >= 4 and includes 'good' Comments on Keywords(The same comment meets the criteria)
db.products.find({
reviews: {
$elemMatch: {
rating: { $gte: 4 },
content: /good/i
}
}
}, { sku: 1, title: 1, reviews: 1 });
// 3. Update:Feature the top-rated comment
db.products.updateOne(
{ sku: 'PHONE-001', 'reviews.rating': { $gte: 5 } },
{ $set: { 'reviews.$.featured': true } }
);
// 4. Query Array Elements:tags Includes '5g' And the array length = 3
db.products.find({ tags: { $all: ['5g', 'amoled'], $size: 3 } });
// 5. Multi-level nested queries:Screen Size = 6.5
db.products.find({ 'specs.screen.size': '6.5' });
الإخراج:
TEXT 📖 للعرض فقط{ acknowledged: true, insertedId: ObjectId('...') } [ { _id: ObjectId('...'), sku: 'PHONE-001', title: 'Smartphone X', reviews: [{ userId: 'user_003', rating: 5, content: 'Best phone ever, amazing good quality', helpful: 25 }] } ] { acknowledged: true, matchedCount: 1, modifiedCount: 1 } [ { _id: ObjectId('...'), sku: 'PHONE-001', tags: ['5g', 'amoled', 'fast-charging'] } ] [ { _id: ObjectId('...'), sku: 'PHONE-001', specs: { screen: { size: '6.5' } } } ]
النتيجة: تُرجع المنتج PHONE-001؛ وفي المصفوفة
reviews، لا يستوفي سوى التقييم الثالث الشرطين —rating >= 4واحتواء التقييم على كلمة «good» — وهو ما يوضح تمامًا قدرة$elemMatchعلى إجراء المطابقة الدقيقة.
❓ أسئلة شائعة
{ tags: '5g' })، فلا حاجة إلى $elemMatch.$elemMatch؟{ "a.b": 1, "a.c": 2 } مع عناصر موجودة في نفس المستند ولكن من مصفوفات مختلفة؛ أما $elemMatch فيجب أن يتطابق مع عناصر من نفس المصفوفة.📖 ملخص
- الاستعلام عن المستندات المتداخلة باستخدام تدوين النقطة:
field.subfield - تطابق مصفوفة ذات عنصر واحد:
{ tags: '5g' } - $all تطابق كل ما يلي:
{ tags: { $all: ['a', 'b'] } } - $elemMatch: مطابقة تامة لعنصر في نفس المصفوفة
- تحديث المصفوفة:
$push/$pull/$pop/$addToSet $تحديث العنصر النائب بالعنصر الأول المطابق
📝 تمارين
- السؤال الأساسي (⭐): البحث عن المنتجات التي تتضمن علاماتها "5g" أو "amoled".
- المشكلة الأساسية (⭐): استخدم الأمر $pull لحذف جميع التعليقات التي حصلت على تقييم أقل من 2.
- مشكلة متقدمة (⭐⭐): استخدم $elemMatch للعثور على المنتجات في التعليقات التي «تبلغ تقييمها 4 أو أكثر وتحتوي على الكلمة المفتاحية "good"».
- تمرين متقدم (⭐⭐): استخدم العنصر النائب $ لتحديث الحقل
helpfulفي تعليقات مستخدم معين. - التحدي (⭐⭐⭐): تنفيذ ميزة «الإعجاب» (مفيد +1) في نظام التعليقات، وتصفية التعليقات ذات التقييم المنخفض، ووضع علامة «تمت مراجعته» على مجموعة من التعليقات دفعة واحدة.