MongoDB

Личный сайт Go-разработчика из Казани

MongoDB is a NoSQL document database for high volume data storage.

MongoDB uses collections and documents for its storage. Each document consists of key-value pairs using JSON-like syntax, similar to a dictionary or JavaScript object.

Likewise, as MongoDB is a NoSQL database, it uses its own query language, Mongo Query Language (MQL) which uses JSON for querying.

Getting Started

Installation

MongoDB can either be installed locally following the instructions here or you can create a remotely-hosted free 512 MB cluster here. Links to videos with instructions on setup are at the bottom.

This tutorial assumes that you have the MongoDB Shell from here. You can also download the graphical tool, MongoDB Compass, down below from the same link.

Components

After installing MongoDB, you will notice there are multiple command line tools. The three most important of which are:

  • mongod - The database server which is responsible for managing data and handling queries
  • mongos - The sharding router, which is needed if data will be distributed across multiple machines
  • mongo - The database shell (using JavaScript) through which we can configure our database

Usually we start the mongod process and then use a separate terminal with mongo to access and modify our collections.

JSON & BSON

While queries in MongoDB are made using a JSON-like* format, MongoDB stores its documents internally in the Binary JSON (BSON format). BSON is not human readable like JSON as it’s a binary encoding. However, this allows for end users to have access to more types than regular JSON, such as an integer or float type. Many other types, such as regular expressions, dates, or raw binary are supported too.

Here is the full list of all types that are supported.

  • We refer JSON-like to mean JSON but with these extended types. For example, you can make queries directly with a regular expression or timestamp in MongoDB and you can receive data that has those types too.
1///////////////////////////////////////////////////////// 2/////////////////// Getting Started ///////////////////// 3///////////////////////////////////////////////////////// 4 5// Start up the mongo database server 6// NOTE - You will need to do this in a separate terminal as the process will 7// take over the terminal. You may want to use the --fork option 8mongod // --fork 9 10// Connecting to a remote Mongo server 11// mongo "mongodb+srv://host.ip.address/admin" --username your-username 12 13// Mongoshell has a proper JavaScript interpreter built in 143 + 2 // 5 15 16// Show available databases 17// MongoDB comes with the following databases built-in: admin, config, local 18show dbs 19 20// Switch to a new database (pre-existing or about to exist) 21// NOTE: There is no "create" command for a database in MongoDB. 22// The database is created upon data being inserted into a collection 23use employees 24 25// Create a new collection 26// NOTE: Inserting a document will implicitly create a collection anyways, 27// so this is not required 28db.createCollection('engineers') 29db.createCollection('doctors') 30 31// See what collections exist under employees 32show collections 33 34///////////////////////////////////////////////////////// 35// Basic Create/Read/Update/Delete (CRUD) Operations: /// 36///////////////////////////////////////////////////////// 37 38/////////////// Insert (Create) ///////////////////////// 39 40// Insert one employee into the database 41// Each insertion returns acknowledged true or false 42// Every document has a unique _id value assigned to it automatically 43db.engineers.insertOne({ name: "Jane Doe", age: 21, gender: 'Female' }) 44 45// Insert a list of employees into the `engineers` collection 46// Can insert as an array of objects 47db.engineers.insert([ 48 { name: "Foo Bar", age: 25, gender: 'Male' }, 49 { name: "Baz Qux", age: 27, gender: 'Other' }, 50]) 51 52// MongoDB does not enforce a schema or structure for objects 53// Insert an empty object into the `engineers` collection 54db.engineers.insertOne({}) 55 56// Fields are optional and do not have to match rest of documents 57db.engineers.insertOne({ name: "Your Name", gender: "Male" }) 58 59// Types can vary and are preserved on insertion 60// This can require additional validation in some languages to prevent problems 61db.engineers.insert({ name: ['Foo', 'Bar'], age: 3.14, gender: true }) 62 63// Objects or arrays can be nested inside a document 64db.engineers.insertOne({ 65 name: "Your Name", 66 gender: "Female", 67 skilledIn: [ 68 "MongoDB", 69 "NoSQL", 70 ], 71 "date-of-birth": { 72 "date": 1993-07-20T09:44:18.674Z, 73 "age": 26 74 }, 75}) 76 77// We can override the _id field 78// Works fine 79db.engineers.insertOne({ 80 _id: 1, 81 name: "An Engineer", 82 age: 25, 83 gender: "Female", 84}) 85 86// Be careful, as _id must ALWAYS be unique for the collection otherwise 87// the insertion will fail 88// Fails with a WriteError indicating _id is a duplicate value 89db.engineers.insertOne({ 90 _id: 1, 91 name: "Another Engineer", 92 age: 25, 93 gender: "Male", 94}) 95 96// Works fine as this is a different collection 97db.doctors.insertOne({ 98 _id: 1, 99 name: "Some Doctor", 100 age: 26, 101 gender: "Other", 102}) 103 104/////////////////// Find (Read) //////////////////////// 105// Queries are in the form of db.collectionName.find(<filter>) 106// Where <filter> is an object 107 108// Show everything in our database so far, limited to a 109// maximum of 20 documents at a time 110// Press i to iterate this cursor to the next 20 documents 111db.engineers.find({}) 112 113// We can pretty print the result of any find() query 114db.engineers.find({}).pretty() 115 116// MongoDB queries take in a JS object and search for documents with matching 117// key-value pairs 118// Returns the first document matching query 119// NOTE: Order of insertion is not preserved in the database, output can vary 120db.engineers.findOne({ name: 'Foo Bar' }) 121 122// Returns all documents with the matching key-value properties as a cursor 123// (which can be converted to an array) 124db.engineers.find({ age: 25 }) 125 126// Type matters when it comes to queries 127// Returns nothing as all ages above are integer type 128db.engineers.find({ age: '25' }) 129 130// find() supports nested objects and arrays just like create() 131db.engineers.find({ 132 name: "Your Name", 133 gender: "Female", 134 skilledIn: [ 135 "MongoDB", 136 "NoSQL", 137 ], 138 "date-of-birth": { 139 "date": 1993-07-20T09:44:18.674Z, 140 "age": 26 141 }, 142}) 143 144///////////////////////// Update //////////////////////// 145// Queries are in the form of db.collectionName.update(<filter>, <update>) 146// NOTE: <update> will always use the $set operator. 147// Several operators are covered later on in the tutorial. 148 149// We can update a single object 150db.engineers.updateOne({ name: 'Foo Bar' }, { $set: { name: 'John Doe', age: 100 }}) 151 152// Or update many objects at the same time 153db.engineers.update({ age: 25 }, { $set: { age: 26 }}) 154 155// We can use { upsert: true } if we would like it to insert if the document doesn't already exist, 156// or to update if it does 157// Returns matched, upserted, modified count 158db.engineers.update({ name: 'Foo Baz' }, 159 { $set: 160 { 161 age: 26, 162 gender: 'Other' 163 } 164 }, 165 { upsert: true } 166) 167 168/////////////////////// Delete ///////////////////////// 169// Queries are in the form of db.collectionName.delete(<filter>) 170 171// Delete first document matching query, always returns deletedCount 172db.engineers.deleteOne({ name: 'Foo Baz' }) 173 174// Delete many documents at once 175db.engineers.deleteMany({ gender: 'Male' }) 176 177// NOTE: There are two methods db.collection.removeOne(<filter>) and 178// db.collection.removeMany(<filter>) that also delete objects but have a 179// slightly different return value. 180// They are not included here as they have been deprecated in the NodeJS driver. 181 182///////////////////////////////////////////////////////// 183//////////////////// Operators ////////////////////////// 184///////////////////////////////////////////////////////// 185 186// Operators in MongoDB have a $ prefix. For this tutorial, we are only looking 187// at comparison and logical operators, but there are many other types of 188// operators 189 190//////////////// Comparison Operators /////////////////// 191 192// Find all greater than or greater than equal to some condition 193db.engineers.find({ age: { $gt: 25 }}) 194db.engineers.find({ age: { $gte: 25 }}) 195 196// Find all less than or less than equal to some condition 197db.engineers.find({ age: { $lt: 25 }}) 198db.engineers.find({ age: { $lte: 25 }}) 199 200// Find all equal or not equal to 201// Note: the $eq operator is added implicitly in most queries 202db.engineers.find({ age: { $eq: 25 }}) 203db.engineers.find({ age: { $ne: 25 }}) 204 205// Find all that match any element in the array, or not in the array 206db.engineers.find({ age: { $in: [ 20, 23, 24, 25 ]}}) 207db.engineers.find({ age: { $nin: [ 20, 23, 24, 25 ]}}) 208 209//////////////// Logical Operators /////////////////// 210 211// Join two query clauses together 212// NOTE: MongoDB does this implicitly for most queries 213db.engineers.find({ $and: [ 214 gender: 'Female', 215 age: { 216 $gte: 18 217 } 218]}) 219 220// Match either query condition 221db.engineers.find({ $or: [ 222 gender: 'Female', 223 age: { 224 $gte: 18 225 } 226]}) 227 228// Negates the query 229db.engineers.find({ $not: { 230 gender: 'Female' 231}}) 232 233// Must match none of the query conditions 234db.engineers.find({ $nor [ 235 gender: 'Female', 236 age: { 237 $gte: 18 238 } 239]}) 240 241///////////////////////////////////////////////////////// 242//////////////// Database Operations: /////////////////// 243///////////////////////////////////////////////////////// 244 245// Delete (drop) the employees database 246// THIS WILL DELETE ALL DOCUMENTS IN THE DATABASE! 247db.dropDatabase() 248 249// Create a new database with some data 250use example 251db.test.insertOne({ name: "Testing data, please ignore!", type: "Test" }) 252 253// Quit Mongo shell 254exit 255 256// Import/export database as BSON: 257 258// Mongodump to export data as BSON for all databases 259// Exported data is found in under "MongoDB Database Tools/bin/dump" 260// NOTE: If the command is not found, navigate to "MongoDB Database Tools/bin" 261// and use the executable from there mongodump 262 263// Mongorestore to restore data from BSON 264mongorestore dump 265 266// Import/export database as JSON: 267// Mongoexport to export data as JSON for all databases 268mongoexport --collection=example 269 270// Mongoimport to export data as JSON for all databases 271mongoimport --collection=example

Further Reading

Setup Videos

Input Validation

From the examples above, if input validation or structure is a concern, I would take a look at the following ORMs:

  • Mongoose (Node.js) - Input validation through schemas that support types, required values, minimum and maximum values.
  • MongoEngine (Python) - Similar to Mongoose, but I found it somewhat limited in my experience
  • MongoKit (Python) - Another great alternative to MongoEngine that I find easier to use than MongoEngine

For statically strongly typed languages (e.g. Java, C++, Rust), input validation usually doesn’t require a library as they define types and structure at compile time.

Resources

If you have the time to spare, I would strongly recommend the courses on MongoDB University. They’re by MongoDB themselves and go into much more detail while still being concise. They’re a mix of videos and quiz questions and this was how I gained my knowledge of MongoDB.

I would recommend the following video series for learning MongoDB:

Language-specific ones that I used before:

Most of the information above was cross-referenced with the MongoDB docs. Here are the docs for each section:

If you’ve been enjoying MongoDB so far and want to explore intermediate features, I would look at aggregation, indexing, and sharding.

  • Aggregation - useful for creating advanced queries to be executed by the database
  • Indexing allows for caching, which allows for much faster execution of queries
  • Sharding allows for horizontal data scaling and distribution between multiple machines.