When working with Amazon DocumentDB or MongoDB, one of the powerful features is the ability to create deeply nested documents, which can help represent complex, hierarchical data structures. In this article, we’ll dive into how you can handle documents with varying levels of nesting, and explore practical ways to manage and query deeply embedded documents.
Creating a Collection with Two Levels of Embedded Documents
In both Amazon DocumentDB and MongoDB, collections don’t need to be explicitly created. Instead, the collection is created when you insert your first document. Below is an example of inserting a document that has two levels of embedded documents:
db.myCollection.insertOne({
_id: 1,
name: "John Doe",
contact: {
phone: "123-456-7890",
address: {
street: "123 Main St",
city: "Exampleville",
zip: "12345"
}
}
});
Document Structure:
{
_id: 1,
name: "John Doe",
contact: { <-- Level 1
phone: "...",
address: { <-- Level 2
street: "...",
city: "...",
zip: "..."
}
}
}
Verifying the Insertion:
To verify the inserted document, you can run the following command to view it:
db.myCollection.find().pretty()
Inserting a Document with Five Levels of Embedded Documents
Now, let’s create a more complex document with five levels of nested embedded fields:
db.myCollection.insertOne({
_id: 555,
level1: {
level2: {
level3: {
level4: {
level5: {
value: "This is level 5"
}
}
}
}
}
});
Document Structure:
{
_id: 555,
level1: {
level2: {
level3: {
level4: {
level5: {
value: "This is level 5"
}
}
}
}
}
}
Verifying the Insertion:
Again, you can verify the insertion using the following query:
db.myCollection.find({ _id: 555 }).pretty()
Listing the Top 10 Documents Ordered by Nesting Depth
To sort documents by their depth of embedding (nesting), we need to write a script that iterates over all documents, computes their depth, and orders them by the deepest one.
Here’s how you can do it in JavaScript (for mongosh
or MongoDB Shell):
function getMaxDepth(obj, currentDepth = 0) {
if (typeof obj !== 'object' || obj === null) return currentDepth;
let max = currentDepth;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const depth = getMaxDepth(obj[key], currentDepth + 1);
if (depth > max) max = depth;
}
}
return max;
}
let results = [];
db.myCollection.find().forEach(doc => {
const depth = getMaxDepth(doc);
results.push({ _id: doc._id, depth: depth });
});
results.sort((a, b) => b.depth - a.depth);
print("Top 10 documents by nesting depth:");
results.slice(0, 10).forEach(doc => printjson(doc));
Sample Output:
Top 10 documents by nesting depth:
{ "_id": ObjectId("..."), "depth": 12 }
{ "_id": ObjectId("..."), "depth": 11 }
...
{ "_id": ObjectId("..."), "depth": 7 }
Adding More Information to the Top 10 Documents
If you want more details about each document, like name
and createdAt
(if they exist), you can modify the script slightly:
function getMaxDepth(obj, currentDepth = 0) {
if (typeof obj !== 'object' || obj === null) return currentDepth;
let max = currentDepth;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const depth = getMaxDepth(obj[key], currentDepth + 1);
if (depth > max) max = depth;
}
}
return max;
}
let results = [];
db.myCollection.find().forEach(doc => {
const depth = getMaxDepth(doc);
results.push({
_id: doc._id,
name: doc.name || null,
createdAt: doc.createdAt || null,
depth: depth
});
});
results.sort((a, b) => b.depth - a.depth);
print("Top 10 documents by nesting depth:");
results.slice(0, 10).forEach(doc => printjson(doc));
Example Output:
{
"_id": ObjectId("..."),
"name": "John Doe",
"createdAt": ISODate("2024-10-01T10:00:00Z"),
"depth": 12
}
Investigating the Maximum Nesting Level in a Collection
If you want to explore the maximum level of embedding within a collection, you can iterate through the documents to find the deepest document(s). Here’s how you can do it step by step:
function getMaxDepth(obj, currentDepth = 0) {
if (typeof obj !== 'object' || obj === null) return currentDepth;
let max = currentDepth;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
const depth = getMaxDepth(obj[key], currentDepth + 1);
if (depth > max) max = depth;
}
}
return max;
}
let maxDepth = 0;
let maxDocs = [];
db.myCollection.find().forEach(doc => {
const depth = getMaxDepth(doc);
if (depth > maxDepth) {
maxDepth = depth;
maxDocs = [{ _id: doc._id, depth: depth, name: doc.name || null, createdAt: doc.createdAt || null }];
} else if (depth === maxDepth) {
maxDocs.push({ _id: doc._id, depth: depth, name: doc.name || null, createdAt: doc.createdAt || null });
}
});
print(`📏 Maximum embedding depth found: ${maxDepth}`);
print(`🧾 Documents with max depth:`);
maxDocs.forEach(doc => printjson(doc));
Example Output:
📏 Maximum embedding depth found: 202
🧾 Documents with max depth:
{
_id: ObjectId('684299b8a59156739fc59f39'),
depth: 202,
name: null,
createdAt: null
}
Attempting to Insert a Document with 202 Nested Levels
You might wonder if MongoDB or Amazon DocumentDB will allow you to insert extremely deep documents. Let’s attempt to insert a document with 202 levels of nesting.
let deepDoc = { value: "Level 202" };
for (let i = 201; i >= 1; i--) {
deepDoc = { [`level${i}`]: deepDoc };
}
try {
db.myCollection.insertOne(deepDoc);
print("Unexpected success: Document inserted");
} catch (e) {
print("❌ Expected failure occurred:");
print(e.message);
}
Example Output:
Unexpected success: Document inserted
While we might expect an error due to the depth limitation, it seems MongoDB allows insertion, even with extremely deep nesting.
Conclusion
MongoDB and Amazon DocumentDB provide flexible ways to handle deeply nested documents, which can be useful for complex hierarchical data. From simple two-level embeddings to deeply nested structures with hundreds of levels, the ability to dynamically create and query these documents can be a powerful tool. Understanding how to manage the depth of your data and optimize queries can lead to more efficient data handling in your applications.
Top comments (0)