Introduction to MongoDB — Records and Values
Getting Set Up
Please read the first guide in this series for more information about setting up MongoDB — Installation, Shell, and Database Management.
Bulk Insertion
Yep, you read that right. Like MySQL, you can also insert many records at a single point in time. The same insert()
function takes not only objects but also arrays as input. This time, we will be lazy and create something simple for the next two records.
1 > db.students.insert([
2 {
3 name: "Purushothaman",
4 degree: "Management",
5 email: "purush@example.com"
6 },
7 {
8 name: "Meaow Meaow",
9 degree: "Cat Study",
10 email: "meaow@example.com",
11 phone: ["9850420420"]
12 }
13]);
You can see that the above records are both different. This leads us to the biggest advantage of Document Databases. You don’t need a fixed schema for the records and each record can be any valid JavaScript expression.
Changing schema “on the fly” is the biggest advantage of using NoSQL.
Now, let’s try executing the above insert query on our database.
1 > db.students.insert(
2... [
3... {
4... "name": "Purushothaman",
5... "degree": "Management",
6... "email": "purush@example.com"
7... },
8... {
9... "name": "Meaow Meaow",
10... "degree": "Cat Study",
11... "email": "meaow@example.com",
12... "phone": ["9850420420"]
13... },
14... ]
15... );
16BulkWriteResult({
17 "writeErrors" : [ ],
18 "writeConcernErrors" : [ ],
19 "nInserted" : 2,
20 "nUpserted" : 0,
21 "nMatched" : 0,
22 "nModified" : 0,
23 "nRemoved" : 0,
24 "upserted" : [ ]
25})
You get the output of the BulkWriteResult
function, where it says nothing for errors and we have a count of '2' for the inserted records. Let's quickly check our table contents by using find()
the method.
1 > db.students.find();
2{ "_id" : ObjectId("592ebe7e8e61243307417cc4"), "name" : "Muhmmad Saim", "degree" : "Cloud Computing", "email" : "saim@example.com", "subjects" : [ { "name" : "Internet Networks", "prof" : "Prof. Awesome Blossom" }, { "name" : "Cloud Computing", "prof" : "Prof. Tech Ninja" }, { "name" : "Web Development", "prof" : "Prof. Chunky Monkey" } ], "phone" : [ "9840035007", "9967728336", "7772844242" ] }
3{ "_id" : ObjectId("592ed5818e61243307417cc5"), "name" : "Purushothaman", "degree" : "Management", "email" : "purush@example.com" }
4{ "_id" : ObjectId("592ed5818e61243307417cc6"), "name" : "Meaow Meaow", "degree" : "Cat Study", "email" : "meaow@example.com", "phone" : [ "9850420420" ] }
5>
We got the three records and each has a different schema, which is great! Since there are too many fields, let’s make it pretty()
:
1 > db.students.find().pretty();
2 {
3 "_id" : ObjectId("592ebe7e8e61243307417cc4"),
4 "name" : "Muhammad Samin",
5 "degree" : "Cloud Computing",
6 "email" : "saim@example.com",
7 "subjects" : [
8 {
9 "name" : "Internet Networks",
10 "prof" : "Prof. Awesome Blossom"
11 },
12 {
13 "name" : "Cloud Computing",
14 "prof" : "Prof. Tech Ninja"
15 },
16 {
17 "name" : "Web Development",
18 "prof" : "Prof. Chunky Monkey"
19 }
20 ],
21 "phone" : [
22 "9840035007",
23 "9967728336",
24 "7772844242"
25 ]
26}
27{
28 "_id" : ObjectId("592ed5818e61243307417cc5"),
29 "name" : "Purushothaman",
30 "degree" : "Management",
31 "email" : "purush@example.com"
32}
33{
34 "_id" : ObjectId("592ed5818e61243307417cc6"),
35 "name" : "Meaow Meaow",
36 "degree" : "Cat Study",
37 "email" : "meaow@example.com",
38 "phone" : [
39 "9850420420"
40 ]
41}
42>
Ah! There we go!
Querying Records
For querying or filtering the fields, we need to pass them as parameter objects in the find()
function. One example will be, let's see if I can get the record with Meaow Meaow
:
1 > db.students.find({"name" : "Meaow Meaow"});
2 { "_id" : ObjectId("592ed5818e61243307417cc6"), "name" : "Meaow Meaow", "degree" : "Cat Study", "email" : "meaow@example.com", "phone" : [ "9850420420" ] }
3>
And, as usual, our pretty()
would return:
1 > db.students.find({"name" : "Meaow Meaow"}).pretty();
2 {
3 "_id" : ObjectId("592ed5818e61243307417cc6"),
4 "name" : "Meaow Meaow",
5 "degree" : "Cat Study",
6 "email" : "meaow@example.com",
7 "phone" : [
8 "9850420420"
9 ]
10}
11 >
This also works for items inside arrays. The find()
the method does exact matches of the values here. Here is one more example of matching a number within an array:
1 > db.students.find({"phone": "9840035007"}).pretty();
2 {
3 "_id" : ObjectId("592ebe7e8e61243307417cc4"),
4 "name" : "Praveen Kumar",
5 "degree" : "Cloud Computing",
6 "email" : "praveen@example.com",
7 "subjects" : [
8 {
9 "name" : "Internet Networks",
10 "prof" : "Prof. Awesome Blossom"
11 },
12 {
13 "name" : "Cloud Computing",
14 "prof" : "Prof. Tech Ninja"
15 },
16 {
17 "name" : "Web Development",
18 "prof" : "Prof. Chunky Monkey"
19 }
20 ],
21 "phone" : [
22 "9840035007",
23 "9967728336",
24 "7772844242"
25 ]
26}
27>
The above command correctly identifies my record and displays it, even though 9840035007
is only one of three numbers present.
Updating Records
The method we use here is db.collection.update()
. It takes up two parameters and a first parameter is an object of a key-value pair for a match that is present in the records. The next parameter is the content that the first parameter is supposed to be replaced with.
So let’s try something like this:
1 > db.students.update(
2 { name: "Muhmmad Saim" },
3 {
4 name: "Muhmmad Saim",
5 degree: "Cloud Computing MSc",
6 email: "samin@example.net",
7 subjects: [
8 {
9 name: "Internet Networks",
10 prof: "Prof. Awesome Blossom"
11 },
12 {
13 name: "Cloud Computing",
14 prof: "Prof. Tech Ninja"
15 },
16 {
17 name: "Web Development",
18 prof: "Prof. Chunky Monkey"
19 }
20 ],
21 phone: ["9840035007", "9967728336", "7772844242"]
22 }
23);
Note 1: You need to give the full object in case of update function, because it makes a replacement of the whole record with the second parameter. If we didn’t set the other values, it will just have one record with just two of the items: the email and the degree.
Note 2: Do not find by name, as I just did, if at all possible. There may be many records matching the same parameter, so use something unique like
_id
.
Trying the above, we get:
1 > db.students.update({"name": "Muhmmad Saim"}, {
2... "name": "Muhmmad Saim",
3... "degree": "Cloud Computing MSc",
4... "email": "saim@example.net",
5... "subjects": [
6... {
7... "name": "Internet Networks",
8... "prof": "Prof. Awesome Blossom"
9... },
10... {
11... "name": "Cloud Computing",
12... "prof": "Prof. Tech Ninja"
13... },
14... {
15... "name": "Web Development",
16... "prof": "Prof. Chunky Monkey"
17... }
18... ],
19... "phone": ["9840035007", "9967728336", "7772844242"]
20... });
21WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
22>
Voila! Let’s see the results:
1 {
2 "nMatched": 1,
3 "nUpserted": 0,
4 "nModified": 1
5 }
It matched one record and it modified it. There’s none upserted (we’ll cover this later). This means that there’s a possibility that it might match, but not update. Let’s run the same command again and see what happens.
Oh dear! It shows the same output. Maybe I was over-enthusiastic.
To see what has changed, we could try to run the find()
function along with our pretty pretty()
function.
1 > db.students.find({"phone": "9840035007"}).pretty();
2{
3 "_id" : ObjectId("592ebe7e8e61243307417cc4"),
4 "name" : "Muhammad Saim",
5 "degree" : "Cloud Computing MSc",
6 "email" : "saim@example.net",
7 "subjects" : [
8 {
9 "name" : "Internet Networks",
10 "prof" : "Prof. Awesome Blossom"
11 },
12 {
13 "name" : "Cloud Computing",
14 "prof" : "Prof. Tech Ninja"
15 },
16 {
17 "name" : "Web Development",
18 "prof" : "Prof. Chunky Monkey"
19 }
20 ],
21 "phone" : [
22 "9840035007",
23 "9967728336",
24 "7772844242"
25 ]
26}
27>
Using `$set`
It’s a pain to add the whole record again, just to change one single value. The good news is, there’s a way around that: using the $set
operator. Say we need to change my email
to saim@example.net
. All that we need to do is:
1 > db.students.update(
2 {
3 name: "Muhammad Saim"
4 },
5 {
6 $set: {
7 email: "saim@example.net"
8 }
9 }
10);
Short and sweet! Now let’s see the output of the above command.
1 > db.students.update({
2... "name": "Muhammad Saim"
3... }, {
4... $set: {
5... "email" : "saim@example.net"
6... }
7... });
8WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
9>
This $set
is somewhat similar to our SQL UPDATE
query. When the query is fired, it keeps the already existing value intact and updates the respective fields. Similar to UPDATE
, $set
shows how many rows the query has affected.
If we see the above result, we can find that the command has matched one and modified one, but not upserted any. If we try to run the same command again, it will give the following result:
WriteResult({ nMatched: 1, nUpserted: 0, nModified: 0 });
Great! Now we know to see that matched
and modified
have different counts. This means, even if you keep sending the same command for an update without the $set
operator, the modification keeps happening all the time, while the $set
operator makes it happen only if there are different values.
Note:
$set
is more performance efficient, if you are making a lot of updates.
Incrementing Numeric Values
There’s another operator that helps us increment numeric values. Consider a record that has some numeric parameter, such as a field called points
. points
are great because they need to increment frequently. Being lazy, I am going to use the $set
function:
1 > db.students.update(
2 {
3 name: "Muhammad Saim"
4 },
5 {
6 $set: {
7 points: 15
8 }
9 }
10);
Executing the above command, we get this:
1 > db.students.update({
2... "name": "Muhammad Saim"
3... }, {
4... $set: {
5... "points" : 15
6... }
7... });
8WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
9>
And, checking if it has been updated, we fire out the find()
command and we get:
1 > db.students.find({"phone": "9840035007"}).pretty();
2{
3 "_id" : ObjectId("592ebe7e8e61243307417cc4"),
4 "name" : "Muhammad Saim",
5 "degree" : "Cloud Computing MSc",
6 "email" : "saim@example.com",
7 "subjects" : [
8 {
9 "name" : "Internet Networks",
10 "prof" : "Prof. Awesome Blossom"
11 },
12 {
13 "name" : "Cloud Computing",
14 "prof" : "Prof. Tech Ninja"
15 },
16 {
17 "name" : "Web Development",
18 "prof" : "Prof. Chunky Monkey"
19 }
20 ],
21 "phone" : [
22 "9840035007",
23 "9967728336",
24 "7772844242"
25 ],
26 "points" : 15
27}
28>
Excellent. We have a points
field in my record with a value of 15
.
That entire process should be clear by now. If something is unclear, look back at the previous section of the guide and/or fire off a question for additional clarity.
Moving on, I complete this article, thereby earning 5 more points. This condition can be produced with one small change:
1> db.students.update(
2 {
3 name: "Muhammad Saim"
4 },
5 {
6 $inc: {
7 points: 5
8 }
9 }
10);
As you can see, changing $set
to $inc
, makes the difference. This is similar to using the augmented assignment operator +=
in standard languages, rather than the assignment operator =
.
1> db.students.update({
2... "name": "Muhammad Saim"
3... }, {
4... $inc: {
5... "points" : 5
6... }
7... });
8WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
9> db.students.find({"phone": "9840035007"}).pretty();
10{
11 "_id" : ObjectId("592ebe7e8e61243307417cc4"),
12 "name" : "Muhammad Saim",
13 "degree" : "Cloud Computing MSc",
14 "email" : "saim@example.com",
15 "subjects" : [
16 {
17 "name" : "Internet Networks",
18 "prof" : "Prof. Awesome Blossom"
19 },
20 {
21 "name" : "Cloud Computing",
22 "prof" : "Prof. Tech Ninja"
23 },
24 {
25 "name" : "Web Development",
26 "prof" : "Prof. Chunky Monkey"
27 }
28 ],
29 "phone" : [
30 "9840035007",
31 "9967728336",
32 "7772844242"
33 ],
34 "points" : 20
35}
36>
Wow, that was an easy increment for me from 15 to 20. Clearly, using $inc
is a great way to increment numeric values.