Suppose we want to create the book
object having the following schema:
book = { name: "Oliver Twist", author: "Charles Dickens", publisher: "Dover Publications", published_on: "December 30, 2002", category: ['Classics', 'Drama'] }
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
On the Mongo CLI, we can add this book
object to our collection using the following command:
> db.books.insert(book)
Suppose we also add the shelf
collection (for example, the floor, the row, the column the shelf is in, the book indexes it maintains, and so on that are part of the shelf
object), which has the following structure:
shelf : { name : 'Fiction', location : { row : 10, column : 3 }, floor : 1 lex : { start : 'O', end : 'P' }, }
Remember, it's quite possible that a few years down the line, some shelf
instances may become obsolete and we might want to maintain their record. Maybe we could have another shelf
instance containing only books that are to be recycled or donated. What can we do? We can approach this as follows:
> db.book.shelf.find()
{ "_id" : ObjectId("4e81e0c3eeef2ac76347a01c"), "name" : "Fiction", "location" : { "row" : 10, "column" : 3 }, "floor" : 1 }
{ "_id" : ObjectId("4e81e0fdeeef2ac76347a01d"), "name" : "Romance", "location" : { "row" : 8, "column" : 5 }, "state" : "window broken", "comments" : "keep away from children" }
You will notice that the second object has more fields, namely comments
and state
. When fetching objects, it's fine if you get extra data. That is the beauty of NoSQL. When the first document is fetched (the one with the name Fiction)
, it will not contain the state
and comments
fields but the second document (the one with the name Romance)
will have them.
Are you worried what will happen if we try to access non-existing data from an object, for example, accessing comments
from the first object fetched? This can be logically resolved—we can check the existence of a key, or default to a value in case it's not there, or ignore its absence. This is typically done anyway in code when we access objects.
Notice that when the schema changed we did not have to add fields in every object with default values like we do when using a SQL database. So there is no redundant information in our database. This ensures that the storage is minimal and in turn the object information fetched will have concise data. So there was no redundancy and no compromise on storage or performance. But wait! There's more.
The way many-to-many relations are managed tells us how we can do more with MongoDB that just cannot be simply done in a relational database. The following is an example:
Each book can have reviews and votes given by customers. We should be able to see these reviews and votes and also maintain a list of top voted books.
If we had to do this in a relational database, this would be somewhat like the relationship diagram shown as follows: (get scared now!)
The vote_count
and review_count
fields are inside the books
table that would need to be updated every time a user votes up/down a book or writes a review. So, to fetch a book along with its votes and reviews, we would need to fire three queries to fetch the information:
SELECT * from book where id = 3;
SELECT * from reviews where book_id = 3;
SELECT * from votes where book_id = 3;
We could also use a join for this:
SELECT * FROM books JOIN reviews ON reviews.book_id = books.id JOIN votes ON votes.book_id = books.id;
3.143.235.227