|
|
|
# Lab 9: 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 10. **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.** Link to video: https://learn.gold.ac.uk/mod/page/view.php?id=399917
|
|
|
|
|
|
|
|
## 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
|
|
|
|
|
|
|
|
## Objectives
|
|
|
|
|
|
|
|
You should work in **pairs** for this exercise. You will be attempting to \`port' the Flucks backend from MySQL to MongoDB. In other words, 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 8), you may make reference to these \`imagined' scenarios.
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## 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 (**Optional**)
|
|
|
|
|
|
|
|
**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 3: Define a document
|
|
|
|
|
|
|
|
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)**.
|
|
|
|
|
|
|
|
+ Adapt some of your app's dummy data so that it fits the JSON format. For example, here is a definition of an **album** for my musicstore app:
|
|
|
|
|
|
|
|
var albumDoc = {
|
|
|
|
title: "Imagine",
|
|
|
|
released: new Date(9 Sep, 1971),
|
|
|
|
artist: { first: "John", last: "Lennon" },
|
|
|
|
tracks: [ "Imagine", "Crippled Inside", "Jealous Guy" ],
|
|
|
|
price: 10.99,
|
|
|
|
genre: "pop"
|
|
|
|
}
|
|
|
|
|
|
|
|
## Task 4: Create a document collection in mongodb
|
|
|
|
|
|
|
|
In mongodb, related documents can be stored together in a **collection**.
|
|
|
|
|
|
|
|
+ To insert a document, use the **insert()** collection method. This inserts a new document in a specific collection. If the collection does not already exist, it is created.
|
|
|
|
|
|
|
|
In the following example, I create a collection called 'albums', and insert in it a single document:
|
|
|
|
|
|
|
|
db.albums.insert({title: "Imagine", released: new Date('1971-09-09'), artist: {first: "John", last: "Lennon"}})
|
|
|
|
|
|
|
|
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.albums.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.albums.find({ price: {$gt: 10} })
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Task 5: Add more documents!
|
|
|
|
|
|
|
|
+ Add a few more documents to your collection (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: https://docs.mongodb.com/v3.4/reference/method/db.collection.find/
|
|
|
|
+ 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.albums.remove({price: {$lt: 20}})
|
|
|
|
The above will remove all documents with a price field where the value is <20.
|
|
|
|
Alternatively, you could remove a specific document by `_id`:
|
|
|
|
|
|
|
|
db.albums.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. all documents with the title "Imagine").
|
|
|
|
|
|
|
|
db.albums.update({title: "Imagine"},{$set: {price:12.99}},{multi: true})
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Extension: Specify 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
|
|
|
|
+ Try referencing a document from one collection, inside a document from another collection. For example, here I reference a document in the **artists** collection within a document in the **albums** collection:
|
|
|
|
|
|
|
|
db.albums.insert({
|
|
|
|
title: "Imagine",
|
|
|
|
artist: {
|
|
|
|
"$ref" : "artists",
|
|
|
|
"$id" : ObjectId("5126bc054aed4daf9e2ab772"),
|
|
|
|
"$db" : "musicstore"
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## 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. |