Lab 4: Introduction to MongoDB and Comparison
MongoDB is a document-based database management system. It fits into the large group of 'NOSQL' (`Not Only SQL'), non-relational database technologies.
This lab session shows you how to perform some basic CRUD (Create Read Update Delete) operations from the JS mongo interactive shell on Igor.
If you cannot access mongo for some reason, there is also a video demonstration on the VLE, under week 5. Please note the video demo has some minor differences compared to what you will encounter on Igor, namely in relation to the login procedure, and there are also some prohibited operations on Igor.
Learning Aims
In this lab you will learn:
- How to connect to the mongodb interactive shell on Igor
- How to create a collection
- How to insert documents in a collection
- How to retrieve documents based on some search criteria
Overview
You should work in pairs for this exercise. You will be attempting to `port' the Flucks backend from MySQL to MongoDB. In other words, to reimplement the database as a MongoDB database.
Working together with your partner, you will need to consider:
- What collections you will create to store similar objects in the database
- What key-value pairs will be defined within a document in a given collection (i.e. how will the documents be structured?)
- How easy was it to complete task 7, compared with a similar operation you did on the MySQL database last week?
- Given the type of operations you might want to perform on data in the Flucks database, which do you think would be more suitable, and why?
For the last objective, you can use your creativity to `imagine' what other functionality the app might eventually have, or what kinds of analysis you might want to do on the Flucks data...when you argue your case on the forum (task 9), you may make reference to these `imagined' scenarios.
Note: You are not expected to port the entire database! Just designing and inserting documents in one or two collections will be sufficient for you to get a feel for this system in relation to MySQL.
Task 1: Start the mongo interactive shell
-
Connect to Igor:
ssh USERNAME@doc.gold.ac.uk
-
Start the mongo shell on Igor:
mongo -u USERNAME -p USERNAME USERNAME
This will start an instance of the mongoDB daemon (mongod), and open up the JS interactive mongo shell.
The first option supplied here says to connect as a specific user (i.e. you); the second option says to prompt for a password (which is also your username); and the last option supplied is the database name. All of you have a database set up whereby the name matches your username.
If you were to communicate with a mongo database using an API (which you would do if you were programming a web-based application in a server-side scripting language), the commands would be similar to those shown here, but not identical.
If starting a local instance of mongo (i.e. on a local installation, not on Igor), you can probably just do:
mongo
Task 2: Create a new database (Local installations only)
Note: This action is PROHIBITED ON IGOR. You can only do this task if on a local instance of mongo. There is no requirement for you to install mongodb locally, so skip this task if it does not apply to you.
-
Just like in MySQL, the first thing you have to do when you start mongo, is tell it which databse you want to work on. To see what databases are available, you can type:
show dbs
-
To switch to another database, type:
use NAMEOFDATABASE
If the database you want to use does not exist, it will be created automatically.
The current database will be available via the db
object variable.
Task 3a: Plan your schema
In this task you should work with your partner to determine what objects should be represented in the database, and in what collections these objects will be housed (remember: an instance of an object will be represented by a single document).
You should then decide what fields (key-value pairs) will be defined in each object (you can just list them at this stage without worrying about the code).
Note: This does not necessarily mean 4 collections with a direct table -> collection mapping...you may decide to remodel the data completely!
Task 3b: Define a document structure
A document-based database such as mongodb is consistent with the object oriented programming paradigm, in a way that a relational database is not. In a relational database, the concept of objects is just that: a concept to help us model the data more easily. Objects don't really exist in a relational database.
In a document-based database however, each document represents a single object. The key-value pairs defined inside it represent the properties of the object.
In Mongodb, documents are compatible with JavaScript Object Notation (JSON).
-
Referring to your Task 3a solution, adapt/remodel some of the dummy data so that it fits the JSON format. For example, here is an example definition of an Account in JSON format:
var Account = { _id: ObjectId(542c2b97bac0595474108b48), username: "jgloo011", email: "jgloo@hotmail.com", password: "$2a$12$OEo1/8zIIyt5rwQn4TzizOJYppoUjYFRJptaq43VUJx.Rwn5llSXa", name: { first: "Janet", last: "Gloob" } }
You could do this on paper or in a text file first! Note: the _id field uniquely identifies every document in a Mongo database, and it gets created automatically when an object is inserted.
You need only do this for one or two of your collections, as you may not have time to do it for the entire schema.
Notice from the above that it is possible to nest objects and arrays within object properties.
Task 4: Create a document collection in mongodb
In mongodb, related documents can be stored together in a collection.
- To create the document for real, use the insert() collection method. This inserts a new document in a specific collection. If the collection does not already exist, it is automatically created.
In the following example, I create a collection called 'Account', and insert in it a single document:
db.accounts.insert({firstname: "Janet", lastname: "Gloob", username: "jgloo011", email: "jgloo@hotmail.com", password: "$2a$12$OEo1/8zIIyt5rwQn4TzizOJYppoUjYFRJptaq43VUJx.Rwn5llSXa"})
The document is automatically given a unique object id. The object id is the value associated with the _id
key.
Task 5: Retrieve the document you just inserted!
-
To check the document was created and to see its
_id
, you can call the find() method on the collection:db.accounts.find()
find() will return all the documents in a collection. In this case, there was only one document to return.
-
To return only documents that meet a certain criteria, you can pass criteria to the find() method like so:
db.accounts.find({ username: "jgloo011" })
Task 5: Add more documents!
- Add a few more documents to your collection (hint: use 'up' on your keyboard to retrieve your previous insert command, and then modify it slightly)
Task 6: Try a more interesting query
- Have a look at the mongo documentation for some inspiration
- For example, you could query using an operator, or you could apply a cursor modifier such as sort() or limit() to alter the execution of the query.
Task 7: Delete a document
-
In mongo, documents can be removed using he remove() method. Criteria can be passed to remove(), just as for find():
db.accounts.remove({username: "jgloo011"})
The above will remove all documents in the accounts collection with a username of `jgloo011'.
Alternatively, you could remove a specific document by _id
:
db.accounts.remove({_id:ObjectId("5847121f0c40b18bec6d4ccd")})
If no criteria are specified, remove() will remove all the documents in a collection!
It can sometimes be preferable to use the removeOne() method, which will remove only the first document that is found which matches the criteria.
Task 8: Update a document
Documents can be altered using the update() collection method. This method expects a query argument (to tell mongo what objects should be affected), an update argument (to tell it what changes to make), and an optional options argument (alters how the query is executed).
-
In the following example, the multi option has been set to true, to ensure the changes are applied to all documents that match the query criteria (i.e. to all documents with a specific image url).
db.flucks.update({img_url: "https://pbs.twimg.com/media/DNZ844zVoAA0z_x.jpg"},{$set: {img_url:"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSdolGLviByI1PEjzD8jQfDwYRURYRSxwOWeUgLTHoYWP79ezXW"}},{multi: true})
Extension: Model relations
There are no 'logical relations' between objects in a MongoDB database. In your relational database, you modelled logical relations by applying foreign key constraints; MongoDB has no concept of foreign keys.
To create relations between objects in a MongoDB database, you must explicitly reference documents (objects) within other documents.
-
Create a second collection of related documents (for example, if you just created an `accounts' collection, you might now create a collection to house `flucks' or similar).
-
Try referencing a document from one collection, inside a document from another collection. For example, here I reference a document in the accounts collection within a document in the flucks collection:
db.flucks.insert({ timestamp: new Timestamp(), img_url: "https://pbs.twimg.com/media/DNZ844zVoAA0z_x.jpg", account: { "$ref" : "accounts", "$id" : ObjectId("5126bc054aed4daf9e2ab772"), "$db" : "USERNAME" } })
Note: the $db
field specifies a database name. If on Igor, this will always be your username.
Task 9: Create a case for or against porting Flucks to MongoDB
Under week 5 on the VLE there is a forum setup for you to state and respond to arguments for or against porting Flucks database to MySQL.
- Decide where you stand on this issue, and come up with a rational argument to support your position.
- Refer to information you have been given about Relational and Non-Relational databases, or things you have found out about them for yourself! The Lecture 5 slides have been published already to help you+ Don't be afraid to use your imagination to `imagine' what directions the Flucks application might take, in terms of future functionality and user-base.