Advanced Topics in Concurrency and Reactive Programming: MongoDB, Mongoose Majeed Kassis
MongoDB First released in 2007 Written in C++ MongoDB (from "humongous") is a cross-platform document- oriented database. Data storage is cheap! a NoSQL database Not a table-based relational database! Uses JSON-like documents with dynamic schemas instead. Document-oriented style.
NoSQL vs SQL: Terminology MongoDB RDBMS Collection Table Document Row (Record) Index Embedded Document Join Reference Foreign Key
Document
Collection
Document Data Model: Example Relational MongoDB { first_name: ‘Paul’, surname: ‘Miller’, city: ‘London’, location: [45.123,47.232], cars: [ { model: ‘Bentley’, year: 1973, value: 100000, … }, { model: ‘Rolls Royce’, year: 1965, value: 330000, … } } Instead of having two tables with a foreign keys, we have a document with a nested document inside it.
Benefits of the Document Model Agility and flexibility Data model supports business change Rapidly iterate to meet new requirements Intuitive, natural data representation Eliminates ORM layer Developers are more productive SQL can be a daunting task: Schemas, ORM Layers Reduces the need for joins, disk seeks Programming is more simple Performance delivered at scale
MongoDB Features { first_name: ‘Paul’, surname: ‘Miller’, Rich Queries Find Paul’s cars Find everybody in London with a car built between 1970 and 1980 { first_name: ‘Paul’, surname: ‘Miller’, city: ‘London’, location: [45.123,47.232], cars: [ { model: ‘Bentley’, year: 1973, value: 100000, … }, { model: ‘Rolls Royce’, year: 1965, value: 330000, … } } Geospatial Find all of the car owners within 5km of Trafalgar Sq. Text Search Find all the cars described as having leather seats Aggregation Calculate the average value of Paul’s car collection Map Reduce What is the ownership pattern of colors by geography over time? (is purple trending up in China?)
Referencing: Example Contacts { _id : 2, name : “Mark Mark”, title : “VP, New Product Development”, company : “Apple Computer”, phone : “408-996-1010”, address : { “$ref”: Addresses, “$id”: 1 } Addresses { _id : ObjectId(1), street : “10260 Bandley Dr”, city : “Cupertino”, state : “CA”, zip_code : ”95014”, country : “USA” } Code: >var user = db.users.findOne({"name":“Mark Mark"}) //finds Contact >var dbRef = user.address //retrieves its ‘address’ object reference >db[dbRef.$ref].findOne({"_id":(dbRef.$id)}) //gets its Address object
Schemas are flexible! { name : “Steven Jobs”, title : “VP, New Product Development”, company : “Apple Computer”, address : { street : “10260 Bandley Dr”, city : “Cupertino”, state : “CA”, zip_code : ”95014” }, phone : “408-996-1010” } { name : “Larry Page”, url : “http://google.com/”, title : “CEO”, company : “Google!”, email : “larry@google.com”, address : { street : “555 Bryant, #106”, city : “Palo Alto”, state : “CA”, zip_code : “94301” } phone : “650-618-1499”, fax : “650-330-0100”
MonogoDB implements CRUD Create Operations Create or insert operations add new documents to a collection. If the collection does not exist, insert operations will create the collection. Read Operations Read operations retrieves documents from a collection. Queries a collection for documents. Update Operations Update operations modify existing documents in a collection. Delete Operations Delete operations remove documents from a collection.
Insert Operations: InsertOne/InsertMany
Read Operation: find
Update Operations:UpdateOne/UpdateMany/replaceOne
Delete Operations: deleteOne/deleteMany
Mongoose Mongoose provides: It includes: a straight-forward schema-based solution to model application data. It includes: Built-in type casting Validation Query building Business Logic hooks Mongoose only adds schemas for the application data. Mongoose does not enforce the schemas on MongoDB!
Mongoose: The Object-Document Modeler Mongoose model objects provide structure to the data. Allows the programmer to manage the model inside the application. This is in contrary to SQL databases where management is done on the database itself, away from the programmer’s control. Models provide consistent naming and typing. Allows for easier interaction with data stored in the database. Mongoose was built as Object-Document Modeler (ODM). Which means it couples each document found in the database with an object suitable for it. That object is used to access and modify the database data specific for this object type.
How does Mongoose work? Mongoose opens a pool of five reusable connections when it connects to a MongoDB database. This pool of connections is shared between all requests! Best practice: Open the connection at application starts up. Leave it open until application shut down. Mongoose can handle multiple databases Each connected can be made to specific database inside MongoDB. var usrDB = mongoose.createConnection(dbURIUsr);
Setting up the MongoDB Installing and Running MongoDB: npm install mongodb MongoDB Compass for DB visualization, and make some DB, lets say ‘mern’ Run mongoDB using “mongod” file Now MongoDB is ready for connecting Configuring MongoDB in Nodejs application: Always connect from server side JS file. Preferably ‘app.js’ or ‘server.js’ file, being your main server file. Create ‘configure.js’ file containing path to MongoDB server:
Getting Started with Mongoose Installing: Useful Links: Package Info: https://www.npmjs.com/package/mongoose API: http://mongoosejs.com/docs/api.html Import: (both are applicable) import mongoose from 'mongoose'; const mongoose = require('mongoose'); $ npm install mongoose
Connecting to MongoDB using Mongoose In the main server file: Where: We use Javascript Promises to be Mongoose Promises.
Mongoose Naming Conventions Collection: Contains many Documents Contains many “entries”, “rows” Document: Contains one entry of data Schema: Used to model one entry of data A Schema contains multiple paths. Path: Path is a pair of key:value Each path is a one entry of the document. One value of the row.
Data Types used in Mongoose String Convert it to uppercase/lowercase Trim data prior to saving A regular expression that can limit data allowed to be saved during the validation process An enum that can define a list of strings that are valid Number Max Min Date Buffer Used to store binary data Boolean Mixed Allows every type ObjectId Allows linking to other document Array List of a certain type. https://code.tutsplus.com/articles/an-introduction-to-mongoose-for-mongodb-and-nodejs--cms-29527
Options for Mongoose Data Types Each data type allows deciding the follows options: a default value a custom validation function indicate a field is required a get function that allows you to manipulate the data before it is returned as an object a set function that allows you to manipulate the data before it is saved to the database create indexes to allow data to be fetched faster
Creating a Schema var schema = new Schema({ name: String, binary: Buffer, living: Boolean, updated: { type: Date, default: Date.now }, age: { type: Number, min: 18, max: 65 }, mixed: Schema.Types.Mixed, _someId: Schema.Types.ObjectId, decimal: Schema.Types.Decimal128, array: [], ofString: [String], ofNumber: [Number], ofDates: [Date], ofBuffer: [Buffer], ofBoolean: [Boolean], ofMixed: [Schema.Types.Mixed], ofObjectId: [Schema.Types.ObjectId], ofArrays: [[]], ofArrayOfNumbers: [[Number]], nested: { stuff: { type: String, lowercase: true, trim: true } } }) Creating a new Schema is done by creating a Schema object. The name should be suffixed by “Schema” word to avoid confusion. Each entry in the Schema is made of “Key: Type” pair. Types can be one of many ⇉ You can also define default values, and also limit values. Complete guide: http://mongoosejs.com/docs/schematypes.html
Model: Mapping a Document Models are constructors compiled from the Schema definitions. One instance of these models represent one document which can be saved and retrieved from the database. All document creation and retrieval is handled by these models.
Defining Models and Constructing Documents Creating a Schema: Constructing Documents using defined Schema:
Querying the Database: find and where Finding documents using find: Finding documents using where: Chaining: (this can be done with all functions) Note: “callback” is a function you define to be executed on the result. This is done due to the asynchronous nature of MongoDB functions. User.find({age: {$gte: 21, $lte: 65}}, callback); User.where('age').gte(21).lte(65).exec(callback); User .where('age').gte(21).lte(65) .where('name', /^b/i) ... etc http://mongoosejs.com/docs/api.html#model_Model.where