diff --git a/docs/MongoDB/Advanced MongoDB/_category.json b/docs/MongoDB/Advanced MongoDB/_category.json new file mode 100644 index 000000000..7235a04b4 --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/_category.json @@ -0,0 +1,8 @@ +{ + "label": "Advanced MongoDB", + "position": 25, + "link": { + "type": "generated-index", + "description": "Dive deeper into advanced MongoDB concepts and techniques." + } +} \ No newline at end of file diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-advanced-indexing.md b/docs/MongoDB/Advanced MongoDB/mongodb-advanced-indexing.md new file mode 100644 index 000000000..17d1afc4f --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-advanced-indexing.md @@ -0,0 +1,233 @@ +--- +id: mongodb-advanced-indexing +title: MongoDB - Advanced Indexing +sidebar_label: Advanced Indexing +sidebar_position: 6 +tags: [mongodb, indexing, array indexing, sub-document indexing] +description: Learn how to create advanced indexes in MongoDB, including indexing array fields and sub-document fields for optimized query performance. +--- + +## Indexing Array Fields + +We have inserted the following document in the collection named `users`: + +```javascript +db.users.insert( + { + "address": { + "city": "Los Angeles", + "state": "California", + "pincode": "123" + }, + "tags": [ + "music", + "cricket", + "blogs" + ], + "name": "Tom Benzamin" + } +) +``` + +The above document contains an `address` sub-document and a `tags` array. + +### Creating an Index on Array Fields + +Suppose we want to search user documents based on the user’s tags. For this, we will create an index on the `tags` array in the collection. + +Creating an index on an array in turn creates separate index entries for each of its fields. So in our case, when we create an index on the `tags` array, separate indexes will be created for its values `music`, `cricket`, and `blogs`. + +To create an index on the `tags` array, use the following code: + +```javascript +db.users.createIndex({"tags":1}) +``` + +```json +{ + "createdCollectionAutomatically" : false, + "numIndexesBefore" : 2, + "numIndexesAfter" : 3, + "ok" : 1 +} +``` + +After creating the index, we can search on the `tags` field of the collection like this: + +```javascript +db.users.find({tags:"cricket"}).pretty() +``` + +```json +{ + "_id" : ObjectId("5dd7c927f1dd4583e7103fdf"), + "address" : { + "city" : "Los Angeles", + "state" : "California", + "pincode" : "123" + }, + "tags" : [ + "music", + "cricket", + "blogs" + ], + "name" : "Tom Benzamin" +} +``` + +To verify that proper indexing is used, use the following `explain` command: + +```javascript +db.users.find({tags:"cricket"}).explain() +``` + +This gives you the following result: + +```json +{ + "queryPlanner" : { + "plannerVersion" : 1, + "namespace" : "mydb.users", + "indexFilterSet" : false, + "parsedQuery" : { + "tags" : { + "$eq" : "cricket" + } + }, + "queryHash" : "9D3B61A7", + "planCacheKey" : "04C9997B", + "winningPlan" : { + "stage" : "FETCH", + "inputStage" : { + "stage" : "IXSCAN", + "keyPattern" : { + "tags" : 1 + }, + "indexName" : "tags_1", + "isMultiKey" : false, + "multiKeyPaths" : { + "tags" : [ ] + }, + "isUnique" : false, + "isSparse" : false, + "isPartial" : false, + "indexVersion" : 2, + "direction" : "forward", + "indexBounds" : { + "tags" : [ + "[\"cricket\", \"cricket\"]" + ] + } + } + }, + "rejectedPlans" : [ ] + }, + "serverInfo" : { + "host" : "Krishna", + "port" : 27017, + "version" : "4.2.1", + "gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e" + }, + "ok" : 1 +} +``` + +The above command resulted in `"stage" : "IXSCAN", "indexName" : "tags_1"` which confirms that proper indexing is used. + +## Indexing Sub-Document Fields + +Suppose that we want to search documents based on `city`, `state`, and `pincode` fields. Since all these fields are part of the `address` sub-document field, we will create an index on all the fields of the sub-document. + +For creating an index on all the three fields of the sub-document, use the following code: + +```javascript +db.users.createIndex({"address.city":1,"address.state":1,"address.pincode":1}) +``` + +```json +{ + "numIndexesBefore" : 4, + "numIndexesAfter" : 4, + "note" : "all indexes already exist", + "ok" : 1 +} +``` + +Once the index is created, we can search for any of the sub-document fields utilizing this index as follows: + +```javascript +db.users.find({"address.city":"Los Angeles"}).pretty() +``` + +```json +{ + "_id" : ObjectId("5dd7c927f1dd4583e7103fdf"), + "address" : { + "city" : "Los Angeles", + "state" : "California", + "pincode" : "123" + }, + "tags" : [ + "music", + "cricket", + "blogs" + ], + "name" : "Tom Benzamin" +} +``` + +Remember that the query expression has to follow the order of the index specified. So the index created above would support the following queries: + +```javascript +db.users.find({"address.city":"Los Angeles","address.state":"California"}).pretty() +``` + +```json +{ + "_id" : ObjectId("5dd7c927f1dd4583e7103fdf"), + "address" : { + "city" : "Los Angeles", + "state" : "California", + "pincode" : "123" + }, + "tags" : [ + "music", + "cricket", + "blogs" + ], + "name" : "Tom Benzamin" +} +``` + +### Diagram (Mermaid) + +Here is a visual representation of the document structure and indexing process: + +```mermaid +graph TD; + A[Document: users] + A --> B[Sub-document: address] + A --> C[Array: tags] + B --> D[city] + B --> E[state] + B --> F[pincode] + C --> G[music] + C --> H[cricket] + C --> I[blogs] +``` + +### Notes + +- Indexing array fields in MongoDB creates separate index entries for each value in the array. +- Indexing sub-document fields allows efficient queries on nested fields. +- Ensure the query order matches the index order to fully utilize the indexes. + +### Table + +| Field | Type | Indexed | Description | +|-----------------|------------------|---------|------------------------------------------| +| `address` | Sub-document | Yes | Contains nested fields for address info. | +| `address.city` | String | Yes | City name in the address. | +| `address.state` | String | Yes | State name in the address. | +| `address.pincode`| String | Yes | Pincode in the address. | +| `tags` | Array of Strings | Yes | User's tags for indexing. | diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-analyzing-queries.md b/docs/MongoDB/Advanced MongoDB/mongodb-analyzing-queries.md new file mode 100644 index 000000000..d5d87733e --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-analyzing-queries.md @@ -0,0 +1,196 @@ +--- +id: mongodb-analyzing-queries +title: MongoDB - Analyzing Queries +sidebar_label: Analyzing Queries +sidebar_position: 4 +tags: [mongodb, analyzing queries, $explain, $hint] +description: Learn how to analyze MongoDB queries using $explain and $hint operators to optimize database performance. +--- + +# MongoDB - Analyzing Queries + +Analyzing queries is a very important aspect of measuring how effective the database and indexing design is. We will learn about the frequently used `$explain` and `$hint` queries. + +## Using $explain + +The `$explain` operator provides information on the query, indexes used in a query, and other statistics. It is very useful when analyzing how well your indexes are optimized. + +In the last chapter, we had already created an index for the `users` collection on fields `gender` and `user_name` using the following query: + +```mongodb +db.users.createIndex({gender:1,user_name:1}) +{ + "numIndexesBefore" : 2, + "numIndexesAfter" : 2, + "note" : "all indexes already exist", + "ok" : 1 +} +``` + +We will now use `$explain` on the following query: + +```mongodb +db.users.find({gender:"M"},{user_name:1,_id:0}).explain() +``` + +The above `explain()` query returns the following analyzed result: + +```json +{ + "queryPlanner" : { + "plannerVersion" : 1, + "namespace" : "mydb.users", + "indexFilterSet" : false, + "parsedQuery" : { + "gender" : { + "$eq" : "M" + } + }, + "queryHash" : "B4037D3C", + "planCacheKey" : "DEAAE17C", + "winningPlan" : { + "stage" : "PROJECTION_COVERED", + "transformBy" : { + "user_name" : 1, + "_id" : 0 + }, + "inputStage" : { + "stage" : "IXSCAN", + "keyPattern" : { + "gender" : 1, + "user_name" : 1 + }, + "indexName" : "gender_1_user_name_1", + "isMultiKey" : false, + "multiKeyPaths" : { + "gender" : [ ], + "user_name" : [ ] + }, + "isUnique" : false, + "isSparse" : false, + "isPartial" : false, + "indexVersion" : 2, + "direction" : "forward", + "indexBounds" : { + "gender" : [ + "[\"M\", \"M\"]" + ], + "user_name" : [ + "[MinKey, MaxKey]" + ] + } + } + }, + "rejectedPlans" : [ ] + }, + "serverInfo" : { + "host" : "Krishna", + "port" : 27017, + "version" : "4.2.1", + "gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e" + }, + "ok" : 1 +} +``` + +We will now look at the fields in this result set: + +- **queryPlanner:** Contains details about the query plan, indexes used, and stages involved in executing the query. +- **indexOnly:** Indicates whether the query was covered by an index. +- **cursor:** Specifies the type of cursor used (e.g., `BTreeCursor` for indexed queries). +- **n:** Indicates the number of documents matching the query. +- **nscannedObjects:** Indicates the total number of documents scanned. +- **nscanned:** Indicates the total number of documents or index entries scanned. + +## Using $hint + +The `$hint` operator forces the query optimizer to use the specified index to run a query. This is particularly useful when you want to test the performance of a query with different indexes. For example, the following query specifies the index on fields `gender` and `user_name` to be used for this query: + +```mongodb +db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}) +{ "user_name" : "tombenzamin" } +``` + +To analyze the above query using `$explain`: + +```mongodb +db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain() +``` + +Which gives you the following result: + +```json +{ + "queryPlanner" : { + "plannerVersion" : 1, + "namespace" : "mydb.users", + "indexFilterSet" : false, + "parsedQuery" : { + "gender" : { + "$eq" : "M" + } + }, + "queryHash" : "B4037D3C", + "planCacheKey" : "DEAAE17C", + "winningPlan" : { + "stage" : "PROJECTION_COVERED", + "transformBy" : { + "user_name" : 1, + "_id" : 0 + }, + "inputStage" : { + "stage" : "IXSCAN", + "keyPattern" : { + "gender" : 1, + "user_name" : 1 + }, + "indexName" : "gender_1_user_name_1", + "isMultiKey" : false, + "multiKeyPaths" : { + "gender" : [ ], + "user_name" : [ ] + }, + "isUnique" : false, + "isSparse" : false, + "isPartial" : false, + "indexVersion" : 2, + "direction" : "forward", + "indexBounds" : { + "gender" : [ + "[\"M\", \"M\"]" + ], + "user_name" : [ + "[MinKey, MaxKey]" + ] + } + } + }, + "rejectedPlans" : [ ] + }, + "serverInfo" : { + "host" : "Krishna", + "port" : 27017, + "version" : "4.2.1", + "gitVersion" : "edf6d45851c0b9ee15548f0f847df141764a317e" + }, + "ok" : 1 +} +``` + +## Diagram + +```mermaid +graph TD + A[Query] --> B[$explain] + A --> C[$hint] + B --> D[Query Plan] + C --> D + D --> E[Optimization] +``` + +## Summary Table + +| Operator | Description | Usage Example | +|-----------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------| +| $explain | Provides information on query execution, indexes used, and stats| `db.users.find({gender:"M"},{user_name:1,_id:0}).explain()` | +| $hint | Forces the query to use a specified index | `db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})` | diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-atomic-operations.md b/docs/MongoDB/Advanced MongoDB/mongodb-atomic-operations.md new file mode 100644 index 000000000..10310acc2 --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-atomic-operations.md @@ -0,0 +1,92 @@ +--- +id: mongodb-atomic-operations +title: MongoDB - Atomic Operations +sidebar_label: Atomic Operations +sidebar_position: 5 +tags: [mongodb, atomic operations, findAndModify, embedded documents] +description: Learn how to maintain atomicity in MongoDB by using embedded documents and the findAndModify command for atomic operations. +--- + +# MongoDB - Atomic Operations + +## Model Data for Atomic Operations + +The recommended approach to maintain atomicity is to keep all related information, which is frequently updated together, in a single document using embedded documents. This ensures that all updates for a single document are atomic. + +### Example Scenario + +Assume we have created a collection named `products` and inserted a document in it as shown below: + +```javascript +> db.createCollection("products") +{ "ok" : 1 } + +> db.productDetails.insert({ + "_id": 1, + "product_name": "Samsung S3", + "category": "mobiles", + "product_total": 5, + "product_available": 3, + "product_bought_by": [ + { + "customer": "john", + "date": "7-Jan-2014" + }, + { + "customer": "mark", + "date": "8-Jan-2014" + } + ] +}) +WriteResult({ "nInserted" : 1 }) +``` + +In this document, we have embedded the information of the customer who buys the product in the `product_bought_by` field. Whenever a new customer buys the product, we will first check if the product is still available using the `product_available` field. If available, we will reduce the value of the `product_available` field and insert the new customer's embedded document in the `product_bought_by` field. We will use the `findAndModify` command for this functionality because it searches and updates the document in one go. + +### Atomic Update Example + +```javascript +> db.products.findAndModify({ + query: { _id: 2, product_available: { $gt: 0 } }, + update: { + $inc: { product_available: -1 }, + $push: { product_bought_by: { customer: "rob", date: "9-Jan-2014" } } + } +}) +``` + +Our approach of using embedded documents and the `findAndModify` query ensures that the product purchase information is updated only if the product is available. The whole transaction, being in a single query, is atomic. + +### Non-Atomic Update Example + +In contrast, consider a scenario where we keep the product availability and the purchase information separately. In this case, we first check if the product is available using the first query. Then, in the second query, we update the purchase information. However, it is possible that between the executions of these two queries, another user has purchased the product and it is no longer available. Without knowing this, our second query will update the purchase information based on the result of our first query. This will make the database inconsistent because we have sold a product that is not available. + +### Atomic Operations Diagram + +```mermaid +graph TD; + A[Start] --> B{Check product availability} + B -->|Available| C[Decrease product_available] + C --> D[Add customer to product_bought_by] + D --> E[Operation Successful] + B -->|Not Available| F[Operation Failed] +``` + +### Key Points + +- **Atomicity:** Ensuring all related updates are performed together. +- **Embedded Documents:** Keeping frequently updated related information in a single document. +- **findAndModify:** A MongoDB command to search and update a document in one atomic operation. + +### Table: findAndModify Command + +| Field | Description | +|-------------------|--------------------------------------------------| +| `query` | The selection criteria for the document to update| +| `update` | The modifications to apply | +| `$inc` | Increment a field value | +| `$push` | Append a value to an array | +| `product_available` | Number of products available | +| `product_bought_by` | Array of customers who bought the product | + +By embedding related data and using atomic operations like `findAndModify`, MongoDB ensures data consistency and integrity, even in complex transactions. diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-covered-queries.md b/docs/MongoDB/Advanced MongoDB/mongodb-covered-queries.md new file mode 100644 index 000000000..5ae2157a4 --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-covered-queries.md @@ -0,0 +1,86 @@ +--- +id: mongodb-covered-queries +title: MongoDB - Covered Queries +sidebar_label: Covered Queries +sidebar_position: 3 +tags: [mongodb, covered queries, indexes] +description: Learn about covered queries in MongoDB and how to use them for optimized performance. +--- + +# MongoDB - Covered Queries + +In this chapter, we will learn about covered queries. + +## What is a Covered Query? + +As per the official MongoDB documentation, a covered query is a query in which − + +- All the fields in the query are part of an index. +- All the fields returned in the query are in the same index. + +Since all the fields present in the query are part of an index, MongoDB matches the query conditions and returns the result using the same index without actually looking inside the documents. Since indexes are present in RAM, fetching data from indexes is much faster as compared to fetching data by scanning documents. + +## Using Covered Queries + +To test covered queries, consider the following document in the `users` collection − + +```json +{ + "_id": ObjectId("53402597d852426020000003"), + "contact": "987654321", + "dob": "01-01-1991", + "gender": "M", + "name": "Tom Benzamin", + "user_name": "tombenzamin" +} +``` + +We will first create a compound index for the `users` collection on the fields `gender` and `user_name` using the following query − + +```mongodb +db.users.createIndex({gender:1,user_name:1}) +{ + "createdCollectionAutomatically" : false, + "numIndexesBefore" : 1, + "numIndexesAfter" : 2, + "ok" : 1 +} +``` + +Now, this index will cover the following query − + +```mongodb +db.users.find({gender:"M"},{user_name:1,_id:0}) +{ "user_name" : "tombenzamin" } +``` + +That is to say that for the above query, MongoDB would not go looking into database documents. Instead, it would fetch the required data from indexed data which is very fast. + +Since our index does not include `_id` field, we have explicitly excluded it from the result set of our query, as MongoDB by default returns `_id` field in every query. So the following query would not have been covered inside the index created above − + +```mongodb +db.users.find({gender:"M"},{user_name:1}) +{ "_id" : ObjectId("53402597d852426020000003"), "user_name" : "tombenzamin" } +``` + +Lastly, remember that an index cannot cover a query if − + +- Any of the indexed fields is an array. +- Any of the indexed fields is a subdocument. + +## Diagram + +```mermaid +graph TD + A[Query] --> B[Indexes] + B --> C[Results] + A -->|Direct| C + C -->|Faster| D[Performance] +``` + +## Summary Table + +| Query Type | Description | Performance Impact | +|------------------|-----------------------------------------------------------------------------------------|-----------------------------------------| +| Covered Query | All fields in query and result are part of an index | High - Utilizes indexes only, faster | +| Non-Covered Query| Fields in query or result are not entirely part of an index, may require document scan | Lower - May need to scan documents | diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-database-references.md b/docs/MongoDB/Advanced MongoDB/mongodb-database-references.md new file mode 100644 index 000000000..c7e5f8075 --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-database-references.md @@ -0,0 +1,79 @@ +--- +id: mongodb-database-references +title: MongoDB - Database References +sidebar_label: Database References +sidebar_position: 2 +tags: [mongodb, dbref, references, manual references] +description: Learn how to use database references (DBRefs) in MongoDB. +--- + +# MongoDB - Database References + +As seen in the last chapter of MongoDB relationships, to implement a normalized database structure in MongoDB, we use the concept of Referenced Relationships, also referred to as Manual References, in which we manually store the referenced document's id inside another document. However, in cases where a document contains references from different collections, we can use MongoDB DBRefs. + +## DBRefs vs Manual References + +As an example scenario, where we would use DBRefs instead of manual references, consider a database where we are storing different types of addresses (home, office, mailing, etc.) in different collections (address_home, address_office, address_mailing, etc). Now, when a user collection's document references an address, it also needs to specify which collection to look into based on the address type. In such scenarios where a document references documents from many collections, we should use DBRefs. + +## Using DBRefs + +There are three fields in DBRefs − + +- **$ref** − This field specifies the collection of the referenced document. +- **$id** − This field specifies the `_id` field of the referenced document. +- **$db** − This is an optional field and contains the name of the database in which the referenced document lies. + +Consider a sample user document having DBRef field `address` as shown in the code snippet − + +```json +{ + "_id":ObjectId("53402597d852426020000002"), + "address": { + "$ref": "address_home", + "$id": ObjectId("534009e4d852427820000002"), + "$db": "tutorialspoint" + }, + "contact": "987654321", + "dob": "01-01-1991", + "name": "Tom Benzamin" +} +``` + +The `address` DBRef field here specifies that the referenced address document lies in `address_home` collection under `tutorialspoint` database and has an id of `534009e4d852427820000002`. + +The following code dynamically looks in the collection specified by `$ref` parameter (address_home in our case) for a document with id as specified by `$id` parameter in DBRef. + +```mongodb +var user = db.users.findOne({"name":"Tom Benzamin"}) +var dbRef = user.address +db[dbRef.$ref].findOne({"_id":(dbRef.$id)}) +``` + +The above code returns the following address document present in `address_home` collection − + +```json +{ + "_id" : ObjectId("534009e4d852427820000002"), + "building" : "22 A, Indiana Apt", + "pincode" : 123456, + "city" : "Los Angeles", + "state" : "California" +} +``` + +## Diagram + +```mermaid +graph TD + A[User Document] -->|Manual Reference| B[Address Document] + A -->|DBRef| C[Address Home Collection] + A -->|DBRef| D[Address Office Collection] + A -->|DBRef| E[Address Mailing Collection] +``` + +## Summary Table + +| Approach | Description | Pros | Cons | +|--------------------|---------------------------------------------------------------------------------|---------------------------------------------|----------------------------------------------------| +| Manual References | Store the referenced document's id inside another document | Simple to implement, straightforward | Requires multiple queries, no collection context | +| DBRefs | Store references with `$ref`, `$id`, and `$db` fields specifying collection and id | Includes collection context, more dynamic | Slightly more complex, still requires multiple queries | diff --git a/docs/MongoDB/Advanced MongoDB/mongodb-relationship.md b/docs/MongoDB/Advanced MongoDB/mongodb-relationship.md new file mode 100644 index 000000000..e8312b954 --- /dev/null +++ b/docs/MongoDB/Advanced MongoDB/mongodb-relationship.md @@ -0,0 +1,119 @@ +--- +id: mongodb-relationship +title: MongoDB - Relationships +sidebar_label: Relationships +sidebar_position: 1 +tags: [mongodb, relationships, embedded, referenced] +description: Learn how to model relationships in MongoDB using embedded and referenced approaches. +--- + +# MongoDB - Relationships + +Relationships in MongoDB represent how various documents are logically related to each other. Relationships can be modeled via Embedded and Referenced approaches. Such relationships can be either 1:1, 1:N, N:1 or N:N. + +Let us consider the case of storing addresses for users. So, one user can have multiple addresses making this a 1:N relationship. + +Following is the sample document structure of user document − + +```json +{ + "_id":ObjectId("52ffc33cd85242f436000001"), + "name": "Tom Hanks", + "contact": "987654321", + "dob": "01-01-1991" +} +``` + +Following is the sample document structure of address document − + +```json +{ + "_id":ObjectId("52ffc4a5d85242602e000000"), + "building": "22 A, Indiana Apt", + "pincode": 123456, + "city": "Los Angeles", + "state": "California" +} +``` + +## Modeling Embedded Relationships + +In the embedded approach, we will embed the address document inside the user document. + +```mongodb +db.users.insert({ + { + "_id":ObjectId("52ffc33cd85242f436000001"), + "contact": "987654321", + "dob": "01-01-1991", + "name": "Tom Benzamin", + "address": [ + { + "building": "22 A, Indiana Apt", + "pincode": 123456, + "city": "Los Angeles", + "state": "California" + }, + { + "building": "170 A, Acropolis Apt", + "pincode": 456789, + "city": "Chicago", + "state": "Illinois" + } + ] + } +}) +``` + +This approach maintains all the related data in a single document, which makes it easy to retrieve and maintain. The whole document can be retrieved in a single query such as − + +```mongodb +db.users.findOne({"name":"Tom Benzamin"},{"address":1}) +``` + +Note that in the above query, `db` and `users` are the database and collection respectively. + +:::note +The drawback is that if the embedded document keeps on growing too much in size, it can impact the read/write performance. +::: + +## Modeling Referenced Relationships + +This is the approach of designing normalized relationships. In this approach, both the user and address documents will be maintained separately but the user document will contain a field that will reference the address document's `id` field. + +```json +{ + "_id":ObjectId("52ffc33cd85242f436000001"), + "contact": "987654321", + "dob": "01-01-1991", + "name": "Tom Benzamin", + "address_ids": [ + ObjectId("52ffc4a5d85242602e000000"), + ObjectId("52ffc4a5d85242602e000001") + ] +} +``` + +As shown above, the user document contains the array field `address_ids` which contains `ObjectIds` of corresponding addresses. Using these `ObjectIds`, we can query the address documents and get address details from there. With this approach, we will need two queries: first to fetch the `address_ids` fields from the user document and second to fetch these addresses from the address collection. + +```mongodb +var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1}) +var addresses = db.address.find({"_id":{"$in":result["address_ids"]}}) +``` + +## Diagram + +```mermaid +graph TD + A[User Document] -->|Embedded| B[Address Document] + A -->|Referenced| C[Address Document 1] + A -->|Referenced| D[Address Document 2] +``` + +## Summary Table + +| Approach | Description | Pros | Cons | +|----------|-------------|------|------| +| Embedded | Address documents are embedded within user documents | Easy retrieval, less complex queries | May lead to large documents, impacting performance | +| Referenced | User document references address documents via `ObjectIds` | Normalized data, avoids large documents | Requires multiple queries to retrieve related data | +