content/blog/ribw/mongodb-basic-operations-and-architecture/index.md (view raw)
1```meta
2title: MongoDB: Basic Operations and Architecture
3published: 2020-03-05T04:00:08+00:00
4updated: 2020-04-08T17:36:25+00:00
5```
6
7This is the second post in the MongoDB series, where we will take a look at the [CRUD operations](https://stackify.com/what-are-crud-operations/) they support, the data model and architecture used.
8
9Other posts in this series:
10
11* [MongoDB: an Introduction](/blog/ribw/mongodb-an-introduction/)
12* [MongoDB: Basic Operations and Architecture](/blog/ribw/mongodb-basic-operations-and-architecture/) (this post)
13* [Developing a Python application for MongoDB](/blog/ribw/developing-a-python-application-for-mongodb/)
14
15This post is co-authored wih Classmate, and in it we will take an explorative approach using the `mongo` command line shell to execute commands against the database. It even has TAB auto-completion, which is awesome!
16
17----------
18
19Before creating any documents, we first need to create somewhere for the documents to be in. And before we create anything, the database has to be running, so let’s do that first. If we don’t have a service installed, we can run the `mongod` command ourselves in some local folder to make things easier:
20
21```
22$ mkdir -p mongo-database
23$ mongod --dbpath mongo-database
24```
25
26Just like that, we will have Mongo running. Now, let’s connect to it using the `mongo` command in another terminal (don’t close the terminal where the server is running, we need it!). By default, it connects to localhost, which is just what we need.
27
28```
29$ mongo
30```
31
32## Create
33
34### Create a database
35
36Let’s list the databases:
37
38```
39> show databases
40admin 0.000GB
41config 0.000GB
42local 0.000GB
43```
44
45Oh, how interesting! There’s already some databases, even though we just created the directory where Mongo will store everything. However, they seem empty, which make sense.
46
47Creating a new database is done by `use`-ing a name that doesn’t exist. Let’s call our new database «helloworld».
48
49```
50> use helloworld
51switched to db helloworld
52```
53
54Good! Now the «local variable» called `db` points to our `helloworld` database.
55
56```
57> db
58helloworld
59```
60
61What happens if we print the databases again? Surely our new database will show up now…
62
63```
64> show databases
65admin 0.000GB
66config 0.000GB
67local 0.000GB
68```
69
70…maybe not! It seems Mongo won’t create the database until we create some collections and documents in it. Databases contain collections, and inside collections (which you can think of as tables) we can insert new documents (which you can think of as rows). Like in many programming languages, the dot operator is used to access these «members».
71
72### Create a document
73
74Let’s add a new greeting into the `greetings` collection:
75
76```
77> db.greetings.insert({message: "¡Bienvenido!", lang: "es"})
78WriteResult({ "nInserted" : 1 })
79
80> show collections
81greetings
82
83> show databases
84admin 0.000GB
85config 0.000GB
86helloworld 0.000GB
87local 0.000GB
88```
89
90That looks promising! We can also see our new `helloworld` database also shows up. The Mongo shell actually works on JavaScript-like code, which is why we can use a variant of JSON (BSON) to insert documents (note the lack of quotes around the keys, convenient!).
91
92The [`insert`](https://docs.mongodb.com/manual/reference/method/db.collection.insert/index.html) method actually supports a list of documents, and by default Mongo will assign a unique identifier to each. If we don’t want that though, all we have to do is add the `_id` key to our documents.
93
94```
95> db.greetings.insert([
96... {message: "Welcome!", lang: "en"},
97... {message: "Bonjour!", lang: "fr"},
98... ])
99BulkWriteResult({
100 "writeErrors" : [ ],
101 "writeConcernErrors" : [ ],
102 "nInserted" : 2,
103 "nUpserted" : 0,
104 "nMatched" : 0,
105 "nModified" : 0,
106 "nRemoved" : 0,
107 "upserted" : [ ]
108})
109```
110
111### Create a collection
112
113In this example, we created the collection `greetings` implicitly, but behind the scenes Mongo made a call to [`createCollection`](https://docs.mongodb.com/manual/reference/method/db.createCollection/). Let’s do just that:
114
115```
116> db.createCollection("goodbyes")
117{ "ok" : 1 }
118
119> show collections
120goodbyes
121greetings
122```
123
124The method actually has a default parameter to configure other options, like the maximum size of the collection or maximum amount of documents in it, validation-related options, and so on. These are all described in more details in the documentation.
125
126## Read
127
128To read the contents of a document, we have to [`find`](https://docs.mongodb.com/manual/reference/method/db.collection.find/index.html) it.
129
130```
131> db.greetings.find()
132{ "_id" : ObjectId("5e74829a0659f802b15f18dd"), "message" : "¡Bienvenido!", "lang" : "es" }
133{ "_id" : ObjectId("5e7487b90659f802b15f18de"), "message" : "Welcome!", "lang" : "en" }
134{ "_id" : ObjectId("5e7487b90659f802b15f18df"), "message" : "Bonjour!", "lang" : "fr" }
135```
136
137That’s a bit unreadable for my taste, can we make it more [`pretty`](https://docs.mongodb.com/manual/reference/method/cursor.pretty/index.html)?
138
139```
140> db.greetings.find().pretty()
141{
142 "_id" : ObjectId("5e74829a0659f802b15f18dd"),
143 "message" : "¡Bienvenido!",
144 "lang" : "es"
145}
146{
147 "_id" : ObjectId("5e7487b90659f802b15f18de"),
148 "message" : "Welcome!",
149 "lang" : "en"
150}
151{
152 "_id" : ObjectId("5e7487b90659f802b15f18df"),
153 "message" : "Bonjour!",
154 "lang" : "fr"
155}
156```
157
158Gorgeous! We can clearly see Mongo created an identifier for us automatically. The queries are also JSON, and support a bunch of operators (prefixed by `$`), known as [Query Selectors](https://docs.mongodb.com/manual/reference/operator/query/). Here’s a few:
159
160<table>
161 <thead>
162 <tr>
163 <th>
164 Operation
165 </th>
166 <th>
167 Syntax
168 </th>
169 <th>
170 RDBMS equivalent
171 </th>
172 </tr>
173 </thead>
174 <tbody>
175 <tr>
176 <td>
177 Equals
178 </td>
179 <td>
180 <code>
181 {key: {$eq: value}}
182 </code>
183 <br/>
184 Shorthand:
185 <code>
186 {key: value}
187 </code>
188 </td>
189 <td>
190 <code>
191 where key = value
192 </code>
193 </td>
194 </tr>
195 <tr>
196 <td>
197 Less Than
198 </td>
199 <td>
200 <code>
201 {key: {$lte: value}}
202 </code>
203 </td>
204 <td>
205 <code>
206 where key < value
207 </code>
208 </td>
209 </tr>
210 <tr>
211 <td>
212 Less Than or Equal
213 </td>
214 <td>
215 <code>
216 {key: {$lt: value}}
217 </code>
218 </td>
219 <td>
220 <code>
221 where key <= value
222 </code>
223 </td>
224 </tr>
225 <tr>
226 <td>
227 Greater Than
228 </td>
229 <td>
230 <code>
231 {key: {$gt: value}}
232 </code>
233 </td>
234 <td>
235 <code>
236 where key > value
237 </code>
238 </td>
239 </tr>
240 <tr>
241 <td>
242 Greater Than or Equal
243 </td>
244 <td>
245 <code>
246 {key: {$gte: value}}
247 </code>
248 </td>
249 <td>
250 <code>
251 where key >= value
252 </code>
253 </td>
254 </tr>
255 <tr>
256 <td>
257 Not Equal
258 </td>
259 <td>
260 <code>
261 {key: {$ne: value}}
262 </code>
263 </td>
264 <td>
265 <code>
266 where key != value
267 </code>
268 </td>
269 </tr>
270 <tr>
271 <td>
272 And
273 </td>
274 <td>
275 <code>
276 {$and: [{k1: v1}, {k2: v2}]}
277 </code>
278 </td>
279 <td>
280 <code>
281 where k1 = v1 and k2 = v2
282 </code>
283 </td>
284 </tr>
285 <tr>
286 <td>
287 Or
288 </td>
289 <td>
290 <code>
291 {$or: [{k1: v1}, {k2: v2}]}
292 </code>
293 </td>
294 <td>
295 <code>
296 where k1 = v1 or k2 = v2
297 </code>
298 </td>
299 </tr>
300 </tbody>
301</table>
302
303The operations all do what you would expect them to do, and their names are really intuitive. Aggregating operations with `$and` or `$or` can be done anywhere in the query, nested any level deep.
304
305## Update
306
307Updating a document can be done by using [`save`](https://docs.mongodb.com/manual/reference/method/db.collection.save/index.html) on an already-existing document (that is, the document we want to save has `_id` and it’s in the collection already). If the document is not in the collection yet, this method will create it.
308
309```
310> db.greetings.save({_id: ObjectId("5e74829a0659f802b15f18dd"), message: "¡Bienvenido, humano!", "lang" : "es"})
311WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
312
313> db.greetings.find({lang: "es"})
314{ "_id" : ObjectId("5e74829a0659f802b15f18dd"), "message" : "¡Bienvenido, humano!", "lang" : "es" }
315```
316
317Alternatively, the [`update`](https://docs.mongodb.com/manual/reference/method/db.collection.update/index.html) method takes a query and new value.
318
319```
320> db.greetings.update({lang: "en"}, {$set: {message: "Welcome, human!"}})
321WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
322
323> db.greetings.find({lang: "en"})
324{ "_id" : ObjectId("5e7487b90659f802b15f18de"), "message" : "Welcome, human!", "lang" : "en" }
325```
326
327## Indexing
328
329Creating an index is done with [`createIndex`](https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/index.html):
330
331```
332> db.greetings.createIndex({lang: +1})
333{
334 "createdCollectionAutomatically" : false,
335 "numIndexesBefore" : 1,
336 "numIndexesAfter" : 2,
337 "ok" : 1
338}
339```
340
341Here, we create an ascending index on the lang key. Descending order is done with `-1`. Now a query for `lang` in our three documents will be fast… well maybe iteration over three documents was faster than an index.
342
343## Delete
344
345### Delete a document
346
347I have to confess, I can’t talk French. I learnt it long ago and it’s long forgotten, so let’s remove the translation I copied online from our greetings with [`remove`](https://docs.mongodb.com/manual/reference/method/db.collection.remove/index.html).
348
349```
350> db.greetings.remove({lang: "fr"})
351WriteResult({ "nRemoved" : 1 })
352```
353
354### Delete a collection
355
356We never really used the `goodbyes` collection. Can we get rid of that?
357
358```
359> db.goodbyes.drop()
360true
361```
362
363Yes, it is `true` that we can [`drop`](https://docs.mongodb.com/manual/reference/method/db.collection.drop/index.html) it.
364
365### Delete a database
366
367Now, I will be honest, I don’t really like our `greetings` database either. It stinks. Let’s get rid of it as well:
368
369```
370> db.dropDatabase()
371{ "dropped" : "helloworld", "ok" : 1 }
372```
373
374Yeah, take that! The [`dropDatabase`](https://docs.mongodb.com/manual/reference/method/db.dropDatabase/) can be used to drop databases.
375
376## References
377
378The examples in this post are all fictional, and the methods that could be used where taken from Classmate’s post, and of course [Mongo’s documentation](https://docs.mongodb.com/manual/reference/method/).