all repos — gemini-redirect @ 47e0791f50526bf27eb7cecb031555a1631020de

content/blog/ribw/mongodb-basic-operations-and-architecture/index.md (view raw)

  1+++
  2title = "MongoDB: Basic Operations and Architecture"
  3date = 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 &lt; 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 &lt;= 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 &gt; 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 &gt;= 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/).