الاستعلام عن الحقول والمصفوفات المتداخلة
سيكتب المتعلمون استعلامات باستخدام صيغة النقطة للوصول إلى المستندات الفرعية المضمّنة وعناصر المصفوفات الفردية.
الاستعلام عن الحقول والمصفوفات المتداخلة درس مجاني في MongoDB Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في MongoDB Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة MongoDB Academy 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
Why Nested Queries Matter
One of MongoDB's signature strengths is storing nested sub-documents and arrays inside a document. But this power is only useful if you can also query that nested data efficiently. MongoDB's dot notation lets you reach into any depth of nesting to filter, project, index, and update specific fields.
Without this capability, you would have to load entire documents into your application and filter in code—wasting bandwidth and making indexes useless. Dot notation queries run server-side, benefiting from indexes on nested fields.
Dot Notation for Nested Fields
Dot notation uses a period (.) to navigate into nested sub-documents. The query { 'address.city': 'Chicago' } matches documents where the address field is an object with a city field equal to 'Chicago'. You can chain dots to any depth: 'address.location.lat'.
The key rule: always wrap dot-notation paths in quotes when used as object keys in JavaScript (because the dot would otherwise be parsed as property access). This is a frequent beginner mistake.
// Document structure
// { name: 'Alice', address: { city: 'Chicago', state: 'IL' } }
// Correct: dot notation in quotes
db.users.find({ 'address.city': 'Chicago' });
// Incorrect: this queries for a field literally named 'address.city'
// (a common mistake)
db.users.find({ address: { city: 'Chicago' } });
// This requires the address to be EXACTLY { city: 'Chicago' } — no other fields!
// Deep nesting: 3 levels
db.users.find({ 'address.location.lat': { $gt: 41.5 } });Exact Sub-Document Match vs Dot Notation
There is an important difference between two ways of querying sub-documents:
- Exact match:
{ address: { city: 'Chicago', state: 'IL' } }— requires theaddressfield to be exactly that object, no more fields, in that exact field order - Dot notation:
{ 'address.city': 'Chicago' }— matches any document whereaddress.cityequals 'Chicago', regardless of what other fields address contains
In practice, always use dot notation for sub-document queries. Exact sub-document matches are fragile and rarely what you intend.
// Document: { address: { city: 'Chicago', state: 'IL', zip: '60601' } }
// Exact match - FAILS to find the document (zip field is extra)
db.users.find({ address: { city: 'Chicago', state: 'IL' } });
// Returns 0 results - zip field makes it not an exact match!
// Dot notation - WORKS correctly
db.users.find({ 'address.city': 'Chicago', 'address.state': 'IL' });
// Returns the document regardless of other address fieldsQuerying Arrays: Equality Check
When you query an array field with a simple equality filter, MongoDB checks if the array contains the value—not if the array equals the value. This is one of the most intuitive parts of the MongoDB query model.
For example, if a product has tags: ['electronics', '4K', 'HDR'], then { tags: '4K' } returns this document because the array contains '4K'. You do not need a special operator—array containment is the default behavior for equality filters on array fields.
// Document: { name: 'Smart TV', tags: ['electronics', '4K', 'HDR'] }
// Query: does tags array contain '4K'?
db.products.find({ tags: '4K' });
// Returns the Smart TV document
// Multiple values: documents where tags contains BOTH values
db.products.find({ tags: { $all: ['4K', 'HDR'] } });
// Returns documents with BOTH '4K' AND 'HDR' in tagsQuerying Arrays by Index Position
You can query a specific position within an array using dot notation with the array index: 'arrayField.0' targets the first element, 'arrayField.1' the second, and so on (0-indexed).
This is useful when array order is meaningful—for example, a document with scores: [95, 87, 71] where the first score is always the most recent. You can filter documents where the first score exceeds a threshold: { 'scores.0': { $gt: 90 } }. Use this sparingly—positional queries are fragile if array order changes.
// Document: { player: 'Alice', scores: [95, 87, 71] }
// Array indices: scores.0 = 95, scores.1 = 87, scores.2 = 71
// Find players whose first (most recent) score > 90
db.players.find({ 'scores.0': { $gt: 90 } });
// Find players whose third score is exactly 71
db.players.find({ 'scores.2': 71 });Querying Arrays of Sub-Documents
Arrays often contain sub-documents—for example, an order document might have items: [{sku:'A1',qty:2},{sku:'B2',qty:1}]. Querying fields within array sub-documents uses dot notation: { 'items.sku': 'A1' } matches any order containing an item with sku 'A1'.
However, this can cause false positives: { 'items.sku': 'A1', 'items.qty': 5 } might match a document where sku='A1' and qty=5 exist in different array elements. To require both conditions on the same element, use $elemMatch (covered in a later lesson).
// Document:
// { orderId: 'ORD-1', items: [ {sku:'A1',qty:2}, {sku:'B2',qty:1} ] }
// Find orders containing sku 'A1' (any array element)
db.orders.find({ 'items.sku': 'A1' });
// Dot notation on nested array field
db.orders.find({ 'items.qty': { $gte: 2 } });
// Returns orders where ANY item has qty >= 2
// Combining two array fields - potential false positive!
db.orders.find({ 'items.sku': 'A1', 'items.qty': { $gte: 5 } });
// Matches even if sku=A1 is one element and qty>=5 is another!Indexing Nested and Array Fields
Creating indexes on nested fields and array fields works exactly like indexing top-level fields—you just use dot notation:
db.users.createIndex({ 'address.city': 1 })— index on a nested fielddb.products.createIndex({ tags: 1 })— multikey index on an array field (indexes each element individually)
MongoDB automatically detects that tags is an array and creates a multikey index. Each array element gets its own entry in the index tree. Multikey indexes cannot be used as shard keys in a sharded cluster, but work perfectly for queries on standalone or replica set deployments.
// Index a nested field
db.users.createIndex({ 'address.city': 1 });
// Query: { 'address.city': 'Chicago' } now uses the index
// Multikey index on array field
db.products.createIndex({ tags: 1 });
// Query: { tags: '4K' } now uses the index
// Each tag value gets its own B-tree entry
// Compound index combining top-level and nested field
db.orders.createIndex({ customerId: 1, 'shipping.country': 1 });Projecting Nested Fields
Projections work with dot notation too, letting you return specific nested fields or array elements without retrieving the entire document. This is especially important when documents have large sub-documents you do not always need.
Use { 'address.city': 1, 'address.state': 1 } to include only the city and state from a nested address object. The response will still contain the address object, but only with the projected fields inside it.
// Project only city and state from nested address
db.users.find(
{ 'address.state': 'IL' },
{ name: 1, 'address.city': 1, 'address.state': 1, _id: 0 }
);
// Returns: { name: 'Alice', address: { city: 'Chicago', state: 'IL' } }
// NOT returned: address.zip, address.street, etc.
// Project array field using $slice to limit elements returned
db.posts.find(
{ authorId: userId },
{ title: 1, comments: { $slice: 3 } } // first 3 comments only
);Filtering by Array Length
To query documents where an array field has a specific number of elements, use the $size operator: { tags: { $size: 3 } } matches documents where tags has exactly 3 elements. Note that $size does not work with comparison operators—it only matches an exact count.
To find documents where an array has at least n elements, a common workaround is to index by the array field and filter by the nth element's existence: { 'tags.2': { $exists: true } } means the array has at least 3 elements (index 0, 1, 2).
// Exact array length match
db.products.find({ tags: { $size: 3 } });
// Returns products with exactly 3 tags
// At least 2 elements (index 1 must exist = min length 2)
db.products.find({ 'tags.1': { $exists: true } });
// Array must be empty
db.users.find({ orders: { $size: 0 } });
// OR equivalently:
db.users.find({ orders: [] });Real-World Example: Product Catalog
Let's apply nested and array queries to a realistic product catalog document. A typical e-commerce product has nested specifications and an array of category tags.
Combining dot notation conditions with comparison operators lets you build precise filters like: 'find all laptops that are in stock, have more than 16 GB RAM, support Wi-Fi 6, and belong to the premium category'—all in a single efficient server-side query.
// Sample product document:
// {
// name: 'UltraBook Pro',
// category: 'laptops',
// specs: { ramGB: 32, storageGB: 1000, wifi: 'Wi-Fi 6' },
// tags: ['premium', 'business', 'ultrabook'],
// inStock: true
// }
db.products.find({
category: 'laptops',
inStock: true,
'specs.ramGB': { $gte: 16 },
'specs.wifi': 'Wi-Fi 6',
tags: 'premium'
});Updating Nested and Array Fields
Dot notation is not just for querying—it also works in update operators. Use with dot notation to update a specific nested field without overwriting the entire sub-document: { : { 'address.city': 'Boston' } } changes only the city while all other address fields remain intact.
For arrays, combine dot notation with the positional $ operator to update the first array element that matched the filter: db.orders.updateOne({ 'items.sku': 'A1' }, { : { 'items.$.qty': 5 } }). This is safe for updating one matched array element without knowing its index.
// Update a nested field without overwriting sub-document
db.users.updateOne(
{ _id: userId },
{ : { 'address.city': 'Boston' } }
);
// Only address.city changes; address.street, address.zip unchanged
// Positional operator: update matched array element
db.orders.updateOne(
{ 'items.sku': 'A1' }, // Filter matches array element
{ : { 'items.$.qty': 5 } } // $ = first matched element
);
// Updates qty on the item where sku='A1'Quick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: dot notation uses period-separated paths like 'address.city' to query and project nested sub-document fields at any depth, array equality queries check containment—{ tags: '4K' } matches if the array contains '4K' anywhere, and $size matches arrays of an exact length while positional indexing ('tags.0') targets specific array positions. Next up we connect a Node.js script to MongoDB and perform insert and find operations using the official driver.
الأسئلة الشائعة
هل درس «الاستعلام عن الحقول والمصفوفات المتداخلة» مجاني؟
نعم — نص درس «الاستعلام عن الحقول والمصفوفات المتداخلة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة MongoDB Academy، انتقل إلى CoddyKit PRO. تتضمن دورة MongoDB Academy 4 دروس في المجموع.
ماذا ستتعلم في «الاستعلام عن الحقول والمصفوفات المتداخلة»؟
سيكتب المتعلمون استعلامات باستخدام صيغة النقطة للوصول إلى المستندات الفرعية المضمّنة وعناصر المصفوفات الفردية. تتمرن على MongoDB Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ MongoDB Academy؟
لا تُشترط خبرة سابقة. MongoDB Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «الاستعلام عن الحقول والمصفوفات المتداخلة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس MongoDB Academy هذا؟
نعم. كل درس في MongoDB Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- insertOne وinsertMany
- findOne مقابل find: شرح المؤشرات
- الاستعلام عن الحقول والمصفوفات المتداخلة
- قراءة المستندات باستخدام مشغّل Node.js