النمط المضاد للمصفوفة غير محدودة الحجم
سيحدد المتعلمون الحالات التي يؤدي فيها التضمين إلى مستندات تنمو بلا حدود، ويعيدون هيكلة المخطط لاستخدام الإحالات بدلًا منه.
النمط المضاد للمصفوفة غير محدودة الحجم درس مجاني في MongoDB Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في MongoDB Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة MongoDB Academy 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
What Is an Unbounded Array?
An unbounded array is an array field inside a document that can grow indefinitely over time. If your schema design allows an array to accumulate items without any upper limit—like storing all user comments inside the user document, or all log entries inside an event document—you have an unbounded array anti-pattern. This is one of the most common MongoDB design mistakes.
The 16 MB Document Size Limit
MongoDB enforces a hard document size limit of 16 MB. An unbounded array grows that document over time. A user document that embeds all messages, all activity log entries, or all purchase history will eventually hit this ceiling. When the limit is reached, inserts fail with a BSONObjectTooLarge error, and there is no graceful way to recover without refactoring the schema.
Classic Anti-Pattern Example
Consider embedding all of a user's comments directly inside the user document. Each new comment pushes another element onto the comments array. An active user could write thousands of comments over months. This schema looks harmless at first but will grow the document without bound.
// ANTI-PATTERN: comments array grows forever
db.users.insertOne({
_id: ObjectId('u1'),
name: 'Alice',
comments: [
{ postId: ObjectId('p1'), text: 'Great article!', createdAt: new Date() },
{ postId: ObjectId('p2'), text: 'I disagree...', createdAt: new Date() }
// ... potentially thousands more
]
});Performance Degradation Before the Limit
Even before hitting 16 MB, large documents harm performance. MongoDB must read the entire document into memory for every operation, even if you only need one field. A user document with ten thousand embedded comments wastes RAM and I/O. Additionally, document growth triggers WiredTiger to move documents to new storage locations, causing fragmentation and write amplification.
Index Bloat From Unbounded Arrays
MongoDB creates a multikey index entry for every element in an indexed array. If you index comments.text on an array that grows to ten thousand elements, the index contains ten thousand entries per user. This bloats the index in memory and on disk, slowing down index scans across the entire collection.
Identifying the Anti-Pattern in Your Schema
Ask yourself these questions about any array field: (1) Can this array grow without a business-defined upper bound? (2) Is the data in this array primarily appended and rarely read all at once? (3) Would a single document with this array ever exceed a few kilobytes? If yes to any of these, you likely have an unbounded array that should be refactored.
Refactoring to a Separate Collection
The correct fix is to move the growing items into their own collection and store a reference. Each comment becomes its own document with a userId field pointing to the author. The user document stays lean and the comments collection can grow to billions of rows without any document hitting size limits.
// FIXED: comments live in their own collection
db.comments.insertMany([
{ _id: ObjectId(), userId: ObjectId('u1'), postId: ObjectId('p1'), text: 'Great article!', createdAt: new Date() },
{ _id: ObjectId(), userId: ObjectId('u1'), postId: ObjectId('p2'), text: 'I disagree...', createdAt: new Date() }
]);
// User document stays small
db.users.findOne({ _id: ObjectId('u1') }); // no comments arrayThe Bucket Pattern as an Alternative
Sometimes you still want to group related events together for efficiency—for example, hourly IoT sensor readings. The bucket pattern creates one document per time bucket (e.g., one per hour) with an embedded array of readings for that period. Each bucket is bounded by the time window, so no single document grows unboundedly. This pattern is common in time-series and analytics schemas.
// Bucket pattern: one document per device per hour
db.sensorReadings.insertOne({
deviceId: 'sensor-42',
bucketStart: new Date('2024-01-01T09:00:00Z'),
readings: [
{ ts: new Date('2024-01-01T09:00:10Z'), temp: 22.1 },
{ ts: new Date('2024-01-01T09:00:20Z'), temp: 22.3 }
// bounded to at most ~60 readings per hour bucket
],
count: 2
});Limiting Array Size With Application Logic
Another approach for capped use cases—like showing the last 5 notifications—is to use $push with $slice to keep the array at a fixed maximum length. This way the array never grows beyond a known size. This is acceptable when only the most recent N items matter and older items can be discarded.
// Keep only the 5 most recent notifications
db.users.updateOne(
{ _id: ObjectId('u1') },
{
$push: {
notifications: {
$each: [{ message: 'New follower', createdAt: new Date() }],
$slice: -5 // retain only the last 5 elements
}
}
}
);Detecting Large Documents in Production
To find documents approaching the size limit in a live collection, use the aggregation pipeline with $bsonSize (MongoDB 4.4+). This expression returns the size of a document in bytes, allowing you to identify and prioritise schema refactoring before a production failure occurs.
// Find documents larger than 1 MB in the users collection
db.users.aggregate([
{
$project: {
name: 1,
docSize: { $bsonSize: '$$ROOT' }
}
},
{ $match: { docSize: { $gt: 1048576 } } }, // 1 MB
{ $sort: { docSize: -1 } }
]);Choosing the Right Refactoring Strategy
When you identify an unbounded array, choose your refactoring strategy based on the data's nature:
- Separate collection + reference: for data that needs independent queries or could grow to thousands of items
- Bucket pattern: for time-ordered events grouped by a natural time window
- $push + $slice: for capped recent-items lists where old data can be dropped
Quick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: unbounded arrays grow documents past the 16 MB limit, large embedded arrays cause memory waste, index bloat, and write amplification, and solutions include separate collections, the bucket pattern, or capped arrays with $slice. Next up we build a schema design decision framework to choose embedding or referencing systematically.
الأسئلة الشائعة
هل درس «النمط المضاد للمصفوفة غير محدودة الحجم» مجاني؟
نعم — نص درس «النمط المضاد للمصفوفة غير محدودة الحجم» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- التضمين: علاقات واحد إلى عدد قليل
- الإحالة: علاقات واحد إلى متعدد ومتعدد إلى متعدد
- النمط المضاد للمصفوفة غير محدودة الحجم
- إطار اتخاذ قرارات تصميم المخطط