PolarSPARC |
Hands-on MongoDB :: Part-4
Bhaskar S | 02/13/2021 (UPDATED) |
Introduction
In Part-1, we setup the high-availability 3-node cluster using Docker and got our hands dirty with MongoDB by using the mongo command-line interface.
In Part-2, we got to demonstrate the same set of operations on MongoDB using the programming language drivers for Java and Python.
In Part-3, we got to demonstrate the same set of operations on MongoDB using Spring Boot with Java .
In this part, we will explore more advanced operators for querying and updating MongoDB using the mongo command-line interface.
Hands-on with MongoDB
Let us create a sample dataset for the purposes of demonstration. The sample dataset will have three collections, namely, products, users, and reviews. We will populate few documents in these collections.
An easy way to create the sample dataset is to list all the commands in a file with .js extension and execute that file using the mongo client.
The following are the contents of the file my_mongo.js (which will be placed in the directory $HOME/Downloads/DATA/mongodb) and lists all the commands to create our sample dataset.
db.products.drop(); db.users.drop(); db.reviews.drop(); db.products.insert({ '_id': 'ipad_air3_64', 'name': 'Apple iPad Air 3rd Gen 64G Wifi', 'price': 599.00, 'quantity': 5, 'category': ['electronics', 'tablet', 'apple'] }); db.products.insert({ '_id': 'kindle_hdx_32', 'name': 'Amazon Kindle 8.9 HDX 32G Wifi', 'price': 99.00, 'quantity': 6, 'category': ['electronics', 'tablet', 'amazon'] }); db.products.insert({ '_id': 'iwatch_6_44', 'name': 'Apple iWatch 6 Wifi 44mm', 'price': 899.00, 'quantity': 8, 'category': ['electronics', 'wearable', 'apple'] }); db.products.insert({ '_id': 'nikon_z6', 'name': 'Nikon Z6', 'price': 1299.00, 'quantity': 3, 'category': ['electronics', 'camera', 'mirrorless', 'nikon'] }); db.products.insert({ '_id': 'canon_r5', 'name': 'Canon R5', 'price': 3899.00, 'quantity': 5, 'category': ['electronics', 'camera', 'mirrorless', 'canon'] }); db.products.insert({ '_id': 'mongo_def', 'name': 'MongoDB, The Definitive Guide', 'price': 39.99, 'quantity': 9, 'category': ['books', 'technology', 'oreilly'] }); db.products.insert({ '_id': 'mongo_action', 'name': 'MongoDB in Action', 'price': 49.99, 'quantity': 6, 'category': ['books', 'technology', 'manning'] }); db.products.insert({ '_id': '7_habits', 'name': 'The 7 Habits of Highly Effective People', 'price': 19.99, 'quantity': 11, 'category': ['books', 'audiobook', 'business', 'leadership'] }); db.products.insert({ '_id': 'my_cheese', 'name': 'Who Moved My Cheese', 'price': 8.99, 'quantity': 4, 'category': ['books', 'business', 'self-help'] }); db.users.insert({ '_id': 'alice', 'first': 'Alice', 'last': 'Thompson', 'contact': { 'email': 'alicet@smart.com', 'phone': '123-456-7890', 'zip': '10001' } }); db.users.insert({ '_id': 'bob', 'first': 'Bob', 'last': 'Jones', 'contact': { 'email': 'bob.jones@tall.com', 'phone': '987-654-3210', 'zip': '10002' } }); db.users.insert({ '_id': 'charlie', 'first': 'Charlie', 'last': 'Lee', 'contact': { 'email': 'c_lee@hard.com', 'phone': '234-567-8901', 'zip': '10003' } }); db.users.insert({ '_id': 'frank', 'first': 'Frank', 'last': 'Smith', 'contact': { 'email': 'fsmith@doe.com', 'phone': '987-456-1111', 'zip': '10002' } }); db.users.insert({ '_id': 'george', 'first': 'George', 'last': 'Baker', 'contact': { 'email': 'g_baker@sharp.com', 'phone': '123-654-0987', 'zip': '10001' } }); db.reviews.insert( { 'user_id': 'alice', 'product_id': 'nikon_z6', 'created': new Date(2020, 6, 15), 'rating': 4, 'comments': 'Good mirrorless' } ); db.reviews.insert( { 'user_id': 'alice', 'product_id': 'mongo_def', 'created': new Date(2018, 3, 11), 'rating': 5, 'comments': 'Great book on Mongo', 'recommend': 'yes' } ); db.reviews.insert( { 'user_id': 'alice', 'product_id': 'my_cheese', 'created': new Date(2018, 7, 14), 'rating': 4, 'comments': 'Decent book with moral' } ); db.reviews.insert( { 'user_id': 'bob', 'product_id': 'ipad_air3_64', 'created': new Date(2020, 4, 9), 'rating': 5, 'comments': 'The best tablet in the market' } ); db.reviews.insert( { 'user_id': 'bob', 'product_id': 'iwatch_6_44', 'created': new Date(2020, 10, 19), 'rating': 5, 'comments': 'Love this iWatch' } ); db.reviews.insert( { 'user_id': 'charlie', 'product_id': '7_habits', 'created': new Date(2019, 5, 27), 'rating': 5, 'comments': 'Excellent leadership book' } ); db.reviews.insert( { 'user_id': 'charlie', 'product_id': 'my_cheese', 'created': new Date(2018, 10, 24), 'rating': 3, 'comments': 'An ok book for reading' } ); db.reviews.insert( { 'user_id': 'frank', 'product_id': 'canon_r5', 'created': new Date(2020, 7, 29), 'rating': 4, 'comments': 'Good Mirrorless but pricy' } ); db.reviews.insert( { 'user_id': 'frank', 'product_id': 'iwatch_6_44', 'created': new Date(2020, 6, 5), 'rating': 5, 'comments': 'Excellent wearable', 'recommend': 'yes' } ); db.reviews.insert( { 'user_id': 'frank', 'product_id': 'mongo_action', 'created': new Date(2019, 11, 4), 'rating': 3, 'comments': 'Decent book' } ); db.reviews.insert( { 'user_id': 'george', 'product_id': 'kindle_hdx_32', 'created': new Date(2018, 8, 20), 'rating': 5, 'comments': 'Great ebook reader from Amazon' } );
Notice that each of the documents inserted into the collection products have a key called category whose type is an array of values. This is not possible with a relational database.
Also, take notice of the fact that each of the documents inserted into the collection users have a key called contact whose type is an object with its own key-value pairs. This is also not possible with a relational database.
Now, to process the file $HOME/Downloads/DATA/mongodb/my_mongo.js using the command-line interface mongo (using docker), execute the following command:
$ docker run --rm -it -v $HOME/Downloads/DATA/mongodb/my_mongo.js:/data/my_mongo.js mongo:4.4.3 mongo --host 192.168.1.53 --port 5001 mydb /data/my_mongo.js
The following will be the output:
MongoDB shell version v4.4.3 connecting to: mongodb://192.168.1.53:5001/mydb?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("b4533c0d-3317-47f5-a528-c2eca0027fde") } MongoDB server version: 4.4.3
The above output indicates that there were no errors and the file my_mongo.js was successfully processed.
As indicated in Part-1, ensure to connect to the PRIMARY node and not to the SECONDARY node(s)
To launch the command-line interactive MongoDB client on the PRIMARY node running on the port 5001 using docker, execute the following command:
$ docker run --rm -it mongo:4.4.3 mongo --host 192.168.1.53 --port 5001 mydb
The following will be the output:
MongoDB shell version v4.4.3 connecting to: mongodb://192.168.1.53:5001/mydb?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("2597330c-c633-4cc4-ab54-9efb1a7a34b2") } MongoDB server version: 4.4.3 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see https://docs.mongodb.com/ Questions? Try the MongoDB Developer Community Forums https://community.mongodb.com --- The server generated these startup warnings when booting: 2021-01-23T02:12:39.003+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem 2021-01-23T02:12:39.827+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted --- --- Enable MongoDB's free cloud-based monitoring service, which will then receive and display metrics about your deployment (disk utilization, CPU, operation statistics, etc). The monitoring data will be available on a MongoDB website with a unique URL accessible to you and anyone you share the URL with. MongoDB may use this information to make product improvements and to suggest MongoDB products and deployment options to you. To enable free monitoring, run the following command: db.enableFreeMonitoring() To permanently disable this reminder, run the following command: db.disableFreeMonitoring() --- mongodb-rs:PRIMARY>
Let us now list all the collection(s) in a database by executing the following command:
mongodb-rs:PRIMARY> show collections
The following will be the typical output:
products reviews users
As can be inferred from the Output.3 above, we have created the three collections products, users, and reviews for our sample dataset in the MongoDB database.
One can query a collection using a key whose type is an array. In our sample dataset, we can query the collection products using the key category by executing the following command:
mongodb-rs:PRIMARY> db.products.find({ 'category': 'electronics' })
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : [ "electronics", "camera", "mirrorless", "nikon" ] } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : [ "electronics", "camera", "mirrorless", "canon" ] }
As can be inferred from the Output.4 above, we are able to retrieve all the documents from the collections products that contain electronics as one of the values in the array.
Similarly, one can query a collection using a key whose type is an object (embedded document). In our sample dataset, we can query the collection users using the key contact.zip by executing the following command:
mongodb-rs:PRIMARY> db.users.find({ 'contact.zip': '10001' })
The following will be the typical output:
{ "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } { "_id" : "george", "first" : "George", "last" : "Baker", "contact" : { "email" : "g_baker@sharp.com", "phone" : "123-654-0987", "zip" : "10001" } }
As can be inferred from the Output.5 above, we are able to retrieve all the documents from the collections users that contain the value 10001 for the key zip of the embedded document with key contact.
Now. let us move on to the special operators that can be used in a query. Special operators for query in MongoDB begin with the $ symbol and represent the various comparison and logical operations as listed in the table below.
Query Operator | Description |
---|---|
$gt | Matches values that are greater than the specified value |
$lt | Matches values that are less than the specified value |
$gte | Matches values that are equal to or greater than the specified value |
$lte | Matches values that are less than or equal to the specified value |
$ne | Matches all values that are not equal to the specified value |
$in | Matches any of the values that exist in the specified array |
$nin | Matches values that do not exist in the specified array |
$all | Applicable only to array values and matches arrays that contain all specified values |
$not | Negates the match condition |
$or | Represents the logical OR |
$and | Represents the logical AND |
$nor | Represents the logical NOR |
To query all the documents from the collection products where the price is greater than 299, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'price': { '$gt': 299 }})
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : [ "electronics", "camera", "mirrorless", "nikon" ] } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : [ "electronics", "camera", "mirrorless", "canon" ] }
To query all the documents from the collection products where the price is less than 10, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'price': { '$lt': 10 }})
The following will be the typical output:
{ "_id" : "my_cheese", "name" : "Who Moved My Cheese", "price" : 8.99, "quantity" : 4, "category" : [ "books", "business", "self-help" ] }
To query all the documents from the collection products where the price is greater than 98 and less than 200, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'price': { '$gt': 98, '$lt': 200 }})
The following will be the typical output:
{ "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] }
To query all the documents from the collection products where the price is greater than or equal to 10 and less than or equal to 399, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'price': { '$gte': 10, '$lte': 399 }})
The following will be the typical output:
{ "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : [ "books", "technology", "oreilly" ] } { "_id" : "mongo_action", "name" : "MongoDB in Action", "price" : 49.99, "quantity" : 6, "category" : [ "books", "technology", "manning" ] } { "_id" : "7_habits", "name" : "The 7 Habits of Highly Effective People", "price" : 19.99, "quantity" : 11, "category" : [ "books", "audiobook", "business", "leadership" ] }
To query all the documents from the collection reviews where the created date is greater than or equal to 1/1/2018 and less than or equal to 1/30/2019 (the month January in JavaScript is represented as a 0), execute the following command:
mongodb-rs:PRIMARY> db.reviews.find({ 'created': { '$gte': new Date(2018, 0, 1), '$lte': new Date(2019, 0, 30) }})
The following will be the typical output:
{ "_id" : ObjectId("60272963971af82c1c471910"), "user_id" : "alice", "product_id" : "mongo_def", "created" : ISODate("2018-04-11T00:00:00Z"), "rating" : 5, "comments" : "Great book on Mongo", "recommend" : "yes" } { "_id" : ObjectId("60272963971af82c1c471914"), "user_id" : "charlie", "product_id" : "my_cheese", "created" : ISODate("2018-11-24T00:00:00Z"), "rating" : 3, "comments" : "An ok book for reading" } { "_id" : ObjectId("60272963971af82c1c471918"), "user_id" : "george", "product_id" : "kindle_hdx_32", "created" : ISODate("2018-09-20T00:00:00Z"), "rating" : 5, "comments" : "Great ebook reader from Amazon" }
To query all the documents from the collection users where the first name is not equal to Bob, execute the following command:
mongodb-rs:PRIMARY> db.users.find({ 'first': { '$ne': 'Bob' }})
The following will be the typical output:
{ "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } { "_id" : "charlie", "first" : "Charlie", "last" : "Lee", "contact" : { "email" : "c_lee@hard.com", "phone" : "234-567-8901", "zip" : "10003" } } { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } { "_id" : "george", "first" : "George", "last" : "Baker", "contact" : { "email" : "g_baker@sharp.com", "phone" : "123-654-0987", "zip" : "10001" } }
To query all the documents from the collection products where the category is in tablet or audiobook, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'category': { '$in': ['tablet', 'audiobook'] }})
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } { "_id" : "7_habits", "name" : "The 7 Habits of Highly Effective People", "price" : 19.99, "quantity" : 11, "category" : [ "books", "audiobook", "business", "leadership" ] }
To query all the documents from the collection products where the category is not in tablet or audiobook, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'category': { '$nin': ['tablet', 'audiobook'] }})
The following will be the typical output:
{ "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : [ "electronics", "camera", "mirrorless", "nikon" ] } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : [ "electronics", "camera", "mirrorless", "canon" ] } { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : [ "books", "technology", "oreilly" ] } { "_id" : "mongo_action", "name" : "MongoDB in Action", "price" : 49.99, "quantity" : 6, "category" : [ "books", "technology", "manning" ] } { "_id" : "my_cheese", "name" : "Who Moved My Cheese", "price" : 8.99, "quantity" : 4, "category" : [ "books", "business", "self-help" ] }
To query all the documents from the collection products where the category matches both books and audiobook, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'category': { '$all': ['books', 'audiobook'] }})
The following will be the typical output:
{ "_id" : "7_habits", "name" : "The 7 Habits of Highly Effective People", "price" : 19.99, "quantity" : 11, "category" : [ "books", "audiobook", "business", "leadership" ] }
Until now all the special operators we used were specified in the value part after the key. The logical operators $or, $and, and $nor appear before the key.
To query all the documents from the collection products where the category matches tablet OR mirrorless, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ '$or': [{'category': 'tablet'}, {'category': 'mirrorless'}]})
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : [ "electronics", "camera", "mirrorless", "nikon" ] } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : [ "electronics", "camera", "mirrorless", "canon" ] }
To query all the documents from the collection products where the category matches books AND technology, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ '$and': [{'category': 'books'}, {'category': 'technology'}]})
The following will be the typical output:
{ "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : [ "books", "technology", "oreilly" ] } { "_id" : "mongo_action", "name" : "MongoDB in Action", "price" : 49.99, "quantity" : 6, "category" : [ "books", "technology", "manning" ] }
In the following table are some more special operators that are not for comparison or logical operations, but needed for some real-world scenarios.
Query Operator | Description |
---|---|
$exist | Matches documents that have the specified key |
$regex | Matches documents where values match the specified regular expression (in perl format) |
$mod: [m, n] | Performs a modulo operation on the value of the specified key and matches documents with a specified result. This operator takes 2 parameters - the number to divide by (m) and the remainder (n) |
To query all the documents from the collection reviews that contain the key recommend, execute the following command:
mongodb-rs:PRIMARY> db.reviews.find({ 'recommend': { $exists: true }})
The following will be the typical output:
{ "_id" : ObjectId("60272963971af82c1c471910"), "user_id" : "alice", "product_id" : "mongo_def", "created" : ISODate("2018-04-11T00:00:00Z"), "rating" : 5, "comments" : "Great book on Mongo", "recommend" : "yes" } { "_id" : ObjectId("60272963971af82c1c471916"), "user_id" : "frank", "product_id" : "iwatch_6_44", "created" : ISODate("2020-07-05T00:00:00Z"), "rating" : 5, "comments" : "Excellent wearable", "recommend" : "yes" }
To query all the documents from the collection reviews for which comments contains the text excellent (ignoring the case), execute the following command:
mongodb-rs:PRIMARY> db.reviews.find({ 'comments': { '$regex': 'excellent', '$options': 'i' }})
The following will be the typical output:
{ "_id" : ObjectId("60272963971af82c1c471913"), "user_id" : "charlie", "product_id" : "7_habits", "created" : ISODate("2019-06-27T00:00:00Z"), "rating" : 5, "comments" : "Excellent leadership book" } { "_id" : ObjectId("60272963971af82c1c471916"), "user_id" : "frank", "product_id" : "iwatch_6_44", "created" : ISODate("2020-07-05T00:00:00Z"), "rating" : 5, "comments" : "Excellent wearable", "recommend" : "yes" }
To query all the documents from the collection products for which the quantity is an even number, execute the following command:
mongodb-rs:PRIMARY> db.products.find({ 'quantity': { '$mod': [2, 0] }})
The following will be the typical output:
{ "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } { "_id" : "mongo_action", "name" : "MongoDB in Action", "price" : 49.99, "quantity" : 6, "category" : [ "books", "technology", "manning" ] } { "_id" : "my_cheese", "name" : "Who Moved My Cheese", "price" : 8.99, "quantity" : 4, "category" : [ "books", "business", "self-help" ] }
To display the count of documents from the collection reviews with rating of 4, execute the following command:
mongodb-rs:PRIMARY> db.reviews.count({ 'rating': 4 })
The following will be the typical output:
3
To query all the distinct values of rating in the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.distinct('rating')
The following will be the typical output:
[ 3, 4, 5 ]
Now let us move on to the special operators that can be used with an update. As with the query operators, the special operators for update also begin with the $ symbol and are as listed in the table below.
Update Operator | Description |
---|---|
$inc | Increments the value of the specified key by the specified value |
$set | Sets the value of the specified key. If the specified key does not exist, it will add the specified key with the specified value |
$unset | Removes the specified key from the existing document |
$rename | Renames an existing key to the specified key |
$push | Appends the specified value into the specified array (even if the value already exists). If the specified key is not present in the document, it adds the array field with the value as its element |
$addToSet | Appends the specified value into the specified array only if the value does not already exist in the array |
$pop | Removes the last or first item of the specified array. A value of 1 indicates last while a value of -1 indicates the first |
$pull | Removes all occurences of the specified value from the specified array |
$pullAll | Removes multiple specified values from the specified array |
To query the value of quantity from the collection products with _id of 7_habits, execute the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': '7_habits' }, { 'quantity': 1, '_id': 0 })
The following will be the typical output:
{ "quantity" : 11 }
To increment the quantity in the collection products for the _id of 7_habits by a value of 2, execute the following command:
mongodb-rs:PRIMARY> db.products.update({ '_id': '7_habits' }, { '$inc': { 'quantity': 2 }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now, re-execute the query for the value of quantity from the collection products for the _id of 7_habits by executing the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': '7_habits' }, { 'quantity': 1, '_id': 0 })
The following will be the typical output:
{ "quantity" : 13 }
To decrement the quantity in the collection products for the _id of 7_habits by a value of 4, execute the following command:
mongodb-rs:PRIMARY> db.products.update({ '_id': '7_habits' }, { '$inc': { 'quantity': -4 }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now again re-execute the query for the value of quantity from the collection products for the _id of 7_habits by executing the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': '7_habits' }, { 'quantity': 1, '_id': 0 })
The following will be the typical output:
{ "quantity" : 9 }
To set the value of quantity in the collection products for the _id of 7_habits to a value of 10, execute the following command:
mongodb-rs:PRIMARY> db.products.update({ '_id': '7_habits' }, { '$set': { 'quantity': 10 }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now query the value of quantity from the collection products for the _id of 7_habits by executing the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': '7_habits' }, { 'quantity': 1, '_id': 0 })
The following will be the typical output:
{ "quantity" : 10 }
To query the document from the collection users for the _id of bob, execute the following command:
mongodb-rs:PRIMARY> db.users.findOne({ '_id': 'bob' })
The following will be the typical output:
{ "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" } }
Now to set the value of middle (a new key) in the collection users for the _id of bob with a value of C, execute the following command:
mongodb-rs:PRIMARY> db.users.update({ '_id': 'bob' }, { '$set': { 'middle': 'C' }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now, again query the document from the collection users for the _id of bob by executing the following command:
mongodb-rs:PRIMARY> db.users.findOne({ '_id': 'bob' })
The following will be the typical output:
{ "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" }, "middle" : "C" }
As is evident from the Output.31 above, the key middle with a value of C has been added to the document.
To remove the key middle from the collection users for the _id of bob, execute the following command:
mongodb-rs:PRIMARY> db.users.update({ '_id': 'bob' }, { '$unset': { 'middle': 1 }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now query the document from the collection users for the _id of bob by executing the following command:
mongodb-rs:PRIMARY> db.users.findOne({ '_id': 'bob' })
The output will be similar to the one in Output.29 above.
As is evident from the Output.29 above, the key middle has been deleted from the document.
To query the document from the collection products for the _id of ipad_air3_64, execute the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': 'ipad_air3_64' })
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] }
To append the value ipad to the array of category in the collection products for the _id of ipad_air3_64, execute the following command:
mongodb-rs:PRIMARY> db.products.update({ '_id': 'ipad_air3_64' }, { '$push': { 'category': 'ipad' }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now again query the document from the collection products for the _id of ipad_air3_64 by executing the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': 'ipad_air3_64' })
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple", "ipad" ] }
To remove the value ipad from the array of category in the collection products for the _id of ipad_air_32, execute the following command:
mongodb-rs:PRIMARY> db.products.update({ '_id': 'ipad_air3_64' }, { '$pop': { 'category': 1 }})
The following will be the typical output:
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
Now re-query the document from the collection products for the _id of ipad_air3_64 by executing the following command:
mongodb-rs:PRIMARY> db.products.findOne({ '_id': 'ipad_air3_64' })
The output will be similar to the one in Output.33 above.
The MongoDB Aggregation Framework (using the aggregate() operation) allows one to perform a pipeline of operations (such as matching, grouping, and transformations) on multiple documents in a collection to produce the desired aggregated results. This is similar to the GROUP BY operations in the relational world.
The following are some of the pipeline operators that can be used for performing the aggregation operation on a collection:
Aggregate Operator | Description |
---|---|
$match | Allows one to select a set of documents from a collection based on a criteria |
$group | Allows one to perform an aggregation operation on all documents in the collection such as counts, averages, maximums, or minimums |
$sort | Allows one to sort the documents from the collection based on the specified field(s) |
$unwind | Applies to an array field in a document and splits each array element as a new document (only in memory) |
$project | Allows one select specified field(s) from the documents in the collection |
$limit | Allows one to limit the number of the documents returned in the result |
To select all the documents from the collection reviews where the field user_id has a value of frank, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $match: { user_id: 'frank' } }])
The following will be the typical output:
{ "_id" : ObjectId("602a7b9cca9f13844ae66947"), "user_id" : "frank", "product_id" : "canon_r5", "created" : ISODate("2020-08-29T00:00:00Z"), "rating" : 4, "comments" : "Good Mirrorless but pricy" } { "_id" : ObjectId("602a7b9cca9f13844ae66948"), "user_id" : "frank", "product_id" : "iwatch_6_44", "created" : ISODate("2020-07-05T00:00:00Z"), "rating" : 5, "comments" : "Excellent wearable", "recommend" : "yes" } { "_id" : ObjectId("602a7b9cca9f13844ae66949"), "user_id" : "frank", "product_id" : "mongo_action", "created" : ISODate("2019-12-04T00:00:00Z"), "rating" : 3, "comments" : "Decent book" }
To unwind and split each of the documents from the collection reviews based on each of the elements in the array field category, execute the following command:
mongodb-rs:PRIMARY> db.products.aggregate([{ $unwind: '$category' }])
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "electronics" } { "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "tablet" } { "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "apple" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "electronics" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "tablet" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "amazon" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "electronics" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "wearable" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "apple" } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : "electronics" } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : "camera" } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : "mirrorless" } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : "nikon" } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : "electronics" } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : "camera" } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : "mirrorless" } { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : "canon" } { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : "books" } { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : "technology" } { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : "oreilly" } Type "it" for more
To unwind and split each of the documents from the collection reviews based on each of the elements in the array field category and limit the results to 10 documents, execute the following command:
mongodb-rs:PRIMARY> db.products.aggregate([{ $unwind: '$category' }, { $limit: 10}])
The following will be the typical output:
{ "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "electronics" } { "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "tablet" } { "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : "apple" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "electronics" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "tablet" } { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : "amazon" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "electronics" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "wearable" } { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : "apple" } { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : "electronics" }
NOTICE how the pipeline operators $unwind and $limit are piped together as a sequence of arguments to the aggregate() operator to form the data processing pipeline. Each of the operators in the pipeline are referred to as a Stage.
The following are some of the operators that can be used with the $group pipeline operator for performing the group operations on a collection:
Aggregate Operator | Description |
---|---|
$avg | Computes the average for the values of the specified key from all documents in the collection |
$max | Finds the maximum of the values for the specified key from all documents in the collection |
$min | Finds the minimum of the values for the specified key from all documents in the collection |
$sum | Adds the specified value for all documents in the collection |
To query the number of reviews grouped by each user_id from the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $group : { _id : '$user_id', num_reviews : { $sum : 1 } } }])
The following will be the typical output:
{ "_id" : "charlie", "num_reviews" : 2 } { "_id" : "george", "num_reviews" : 1 } { "_id" : "alice", "num_reviews" : 3 } { "_id" : "bob", "num_reviews" : 2 } { "_id" : "frank", "num_reviews" : 3 }
To query the number of reviews grouped by each user_id from the collection reviews and return the results in a descending sorted order by the number of reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $group : { _id : '$user_id', num_reviews : { $sum : 1 } } }, { $sort: { num_reviews: -1 } }])
The following will be the typical output:
{ "_id" : "alice", "num_reviews" : 3 } { "_id" : "frank", "num_reviews" : 3 } { "_id" : "charlie", "num_reviews" : 2 } { "_id" : "bob", "num_reviews" : 2 } { "_id" : "george", "num_reviews" : 1 }
To query the number of items in the category of books from the collection products, execute the following command:
mongodb-rs:PRIMARY> db.products.aggregate([{ $match: { category: 'books' } }, { $group : { _id : '$category', count : { $sum : 1 } } }])
The following will be the typical output:
{ "_id" : [ "books", "technology", "oreilly" ], "count" : 1 } { "_id" : [ "books", "audiobook", "business", "leadership" ], "count" : 1 } { "_id" : [ "books", "technology", "manning" ], "count" : 1 } { "_id" : [ "books", "business", "self-help" ], "count" : 1 }
Hmmm - this is not what we expected. Now we see why we need the $unwind operator !!!
To query the number of items in the category of books from the collection products the correct way, execute the following command:
mongodb-rs:PRIMARY> db.products.aggregate([{ $unwind: '$category' }, { $match: { category: 'books' } }, { $group : { _id : '$category', count : { $sum : 1 } } }])
The following will be the typical output:
{ "_id" : "books", "count" : 4 }
To query the average rating grouped by each product_id from the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{$group : {_id : '$product_id', average_rating : {$avg : '$rating'}}}])
The following will be the typical output:
{ "_id" : "my_cheese", "average_rating" : 3.5 } { "_id" : "mongo_def", "average_rating" : 5 } { "_id" : "kindle_hdx_32", "average_rating" : 5 } { "_id" : "7_habits", "average_rating" : 5 } { "_id" : "mongo_action", "average_rating" : 3 } { "_id" : "ipad_air3_64", "average_rating" : 5 } { "_id" : "nikon_z6", "average_rating" : 4 } { "_id" : "iwatch_6_44", "average_rating" : 5 } { "_id" : "canon_r5", "average_rating" : 4 }
To select only the fields product_id and rating from all the documents in the collection reviews where the field user_id has a value of frank, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $match: { user_id: 'frank' } }, { $project: { user_id: 1, product_id: 1, rating: 1 } }])
The following will be the typical output:
{ "_id" : ObjectId("602a7b9cca9f13844ae66947"), "user_id" : "frank", "product_id" : "canon_r5", "rating" : 4 } { "_id" : ObjectId("602a7b9cca9f13844ae66948"), "user_id" : "frank", "product_id" : "iwatch_6_44", "rating" : 5 } { "_id" : ObjectId("602a7b9cca9f13844ae66949"), "user_id" : "frank", "product_id" : "mongo_action", "rating" : 3 }
To query the number of reviews grouped by the user_id with a value of frank from the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $match: { user_id: 'frank' } }, { $project: { user_id: 1, product_id: 1, rating: 1 } }, { $group : { _id : '$user_id', num_reviews : { $sum : 1 } } }])
The following will be the typical output:
{ "_id" : "frank", "num_reviews" : 3 }
Each of the document in the collection reviews has two references - one to a document in the collection products via the field product_id and the other to a document in the collection users via the field user_id. One can explicitly write logic to join the two collections or one can use the $lookup pipeline operator to implicitly join the two collections.
The general format of the $lookup operator is as follows:
{
from: 'collection to join with'
localField: 'field from the current input document'
foreignField: 'field in the from: collection'
as: 'output array field'
}
The result of the $lookup operation is that the document in the from: collection is embedded (or joined) into the current input document.
To join and embed each user from the collection users that corresponds to the user_id into the documents from the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $lookup: { from: 'users', localField: 'user_id', foreignField: '_id', as: 'user' } }])
The following will be the typical output:
{ "_id" : ObjectId("602a7b9cca9f13844ae66940"), "user_id" : "alice", "product_id" : "nikon_z6", "created" : ISODate("2020-07-15T00:00:00Z"), "rating" : 4, "comments" : "Good mirrorless", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66941"), "user_id" : "alice", "product_id" : "mongo_def", "created" : ISODate("2018-04-11T00:00:00Z"), "rating" : 5, "comments" : "Great book on Mongo", "recommend" : "yes", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66942"), "user_id" : "alice", "product_id" : "my_cheese", "created" : ISODate("2018-08-14T00:00:00Z"), "rating" : 4, "comments" : "Decent book with moral", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66943"), "user_id" : "bob", "product_id" : "ipad_air3_64", "created" : ISODate("2020-05-09T00:00:00Z"), "rating" : 5, "comments" : "The best tablet in the market", "user" : [ { "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66944"), "user_id" : "bob", "product_id" : "iwatch_6_44", "created" : ISODate("2020-11-19T00:00:00Z"), "rating" : 5, "comments" : "Love this iWatch", "user" : [ { "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66945"), "user_id" : "charlie", "product_id" : "7_habits", "created" : ISODate("2019-06-27T00:00:00Z"), "rating" : 5, "comments" : "Excellent leadership book", "user" : [ { "_id" : "charlie", "first" : "Charlie", "last" : "Lee", "contact" : { "email" : "c_lee@hard.com", "phone" : "234-567-8901", "zip" : "10003" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66946"), "user_id" : "charlie", "product_id" : "my_cheese", "created" : ISODate("2018-11-24T00:00:00Z"), "rating" : 3, "comments" : "An ok book for reading", "user" : [ { "_id" : "charlie", "first" : "Charlie", "last" : "Lee", "contact" : { "email" : "c_lee@hard.com", "phone" : "234-567-8901", "zip" : "10003" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66947"), "user_id" : "frank", "product_id" : "canon_r5", "created" : ISODate("2020-08-29T00:00:00Z"), "rating" : 4, "comments" : "Good Mirrorless but pricy", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66948"), "user_id" : "frank", "product_id" : "iwatch_6_44", "created" : ISODate("2020-07-05T00:00:00Z"), "rating" : 5, "comments" : "Excellent wearable", "recommend" : "yes", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66949"), "user_id" : "frank", "product_id" : "mongo_action", "created" : ISODate("2019-12-04T00:00:00Z"), "rating" : 3, "comments" : "Decent book", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ] } { "_id" : ObjectId("602a7b9cca9f13844ae6694a"), "user_id" : "george", "product_id" : "kindle_hdx_32", "created" : ISODate("2018-09-20T00:00:00Z"), "rating" : 5, "comments" : "Great ebook reader from Amazon", "user" : [ { "_id" : "george", "first" : "George", "last" : "Baker", "contact" : { "email" : "g_baker@sharp.com", "phone" : "123-654-0987", "zip" : "10001" } } ] }
To join and embed each user from the collection users that corresponds to the user_id as well as the product from the collection products that corresponds to the product_id into the documents from the collection reviews, execute the following command:
mongodb-rs:PRIMARY> db.reviews.aggregate([{ $lookup: { from: 'users', localField: 'user_id', foreignField: '_id', as: 'user' } }, { $lookup: { from: 'products', localField: 'product_id', foreignField: '_id', as: 'product' } }])
The following will be the typical output:
{ "_id" : ObjectId("602a7b9cca9f13844ae66940"), "user_id" : "alice", "product_id" : "nikon_z6", "created" : ISODate("2020-07-15T00:00:00Z"), "rating" : 4, "comments" : "Good mirrorless", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ], "product" : [ { "_id" : "nikon_z6", "name" : "Nikon Z6", "price" : 1299, "quantity" : 3, "category" : [ "electronics", "camera", "mirrorless", "nikon" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66941"), "user_id" : "alice", "product_id" : "mongo_def", "created" : ISODate("2018-04-11T00:00:00Z"), "rating" : 5, "comments" : "Great book on Mongo", "recommend" : "yes", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ], "product" : [ { "_id" : "mongo_def", "name" : "MongoDB, The Definitive Guide", "price" : 39.99, "quantity" : 9, "category" : [ "books", "technology", "oreilly" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66942"), "user_id" : "alice", "product_id" : "my_cheese", "created" : ISODate("2018-08-14T00:00:00Z"), "rating" : 4, "comments" : "Decent book with moral", "user" : [ { "_id" : "alice", "first" : "Alice", "last" : "Thompson", "contact" : { "email" : "alicet@smart.com", "phone" : "123-456-7890", "zip" : "10001" } } ], "product" : [ { "_id" : "my_cheese", "name" : "Who Moved My Cheese", "price" : 8.99, "quantity" : 4, "category" : [ "books", "business", "self-help" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66943"), "user_id" : "bob", "product_id" : "ipad_air3_64", "created" : ISODate("2020-05-09T00:00:00Z"), "rating" : 5, "comments" : "The best tablet in the market", "user" : [ { "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" } } ], "product" : [ { "_id" : "ipad_air3_64", "name" : "Apple iPad Air 3rd Gen 64G Wifi", "price" : 599, "quantity" : 5, "category" : [ "electronics", "tablet", "apple" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66944"), "user_id" : "bob", "product_id" : "iwatch_6_44", "created" : ISODate("2020-11-19T00:00:00Z"), "rating" : 5, "comments" : "Love this iWatch", "user" : [ { "_id" : "bob", "first" : "Bob", "last" : "Jones", "contact" : { "email" : "bob.jones@tall.com", "phone" : "987-654-3210", "zip" : "10002" } } ], "product" : [ { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66945"), "user_id" : "charlie", "product_id" : "7_habits", "created" : ISODate("2019-06-27T00:00:00Z"), "rating" : 5, "comments" : "Excellent leadership book", "user" : [ { "_id" : "charlie", "first" : "Charlie", "last" : "Lee", "contact" : { "email" : "c_lee@hard.com", "phone" : "234-567-8901", "zip" : "10003" } } ], "product" : [ { "_id" : "7_habits", "name" : "The 7 Habits of Highly Effective People", "price" : 19.99, "quantity" : 11, "category" : [ "books", "audiobook", "business", "leadership" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66946"), "user_id" : "charlie", "product_id" : "my_cheese", "created" : ISODate("2018-11-24T00:00:00Z"), "rating" : 3, "comments" : "An ok book for reading", "user" : [ { "_id" : "charlie", "first" : "Charlie", "last" : "Lee", "contact" : { "email" : "c_lee@hard.com", "phone" : "234-567-8901", "zip" : "10003" } } ], "product" : [ { "_id" : "my_cheese", "name" : "Who Moved My Cheese", "price" : 8.99, "quantity" : 4, "category" : [ "books", "business", "self-help" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66947"), "user_id" : "frank", "product_id" : "canon_r5", "created" : ISODate("2020-08-29T00:00:00Z"), "rating" : 4, "comments" : "Good Mirrorless but pricy", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ], "product" : [ { "_id" : "canon_r5", "name" : "Canon R5", "price" : 3899, "quantity" : 5, "category" : [ "electronics", "camera", "mirrorless", "canon" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66948"), "user_id" : "frank", "product_id" : "iwatch_6_44", "created" : ISODate("2020-07-05T00:00:00Z"), "rating" : 5, "comments" : "Excellent wearable", "recommend" : "yes", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ], "product" : [ { "_id" : "iwatch_6_44", "name" : "Apple iWatch 6 Wifi 44mm", "price" : 899, "quantity" : 8, "category" : [ "electronics", "wearable", "apple" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae66949"), "user_id" : "frank", "product_id" : "mongo_action", "created" : ISODate("2019-12-04T00:00:00Z"), "rating" : 3, "comments" : "Decent book", "user" : [ { "_id" : "frank", "first" : "Frank", "last" : "Smith", "contact" : { "email" : "fsmith@doe.com", "phone" : "987-456-1111", "zip" : "10002" } } ], "product" : [ { "_id" : "mongo_action", "name" : "MongoDB in Action", "price" : 49.99, "quantity" : 6, "category" : [ "books", "technology", "manning" ] } ] } { "_id" : ObjectId("602a7b9cca9f13844ae6694a"), "user_id" : "george", "product_id" : "kindle_hdx_32", "created" : ISODate("2018-09-20T00:00:00Z"), "rating" : 5, "comments" : "Great ebook reader from Amazon", "user" : [ { "_id" : "george", "first" : "George", "last" : "Baker", "contact" : { "email" : "g_baker@sharp.com", "phone" : "123-654-0987", "zip" : "10001" } } ], "product" : [ { "_id" : "kindle_hdx_32", "name" : "Amazon Kindle 8.9 HDX 32G Wifi", "price" : 99, "quantity" : 6, "category" : [ "electronics", "tablet", "amazon" ] } ] }
References