Mongoose

  1. Overview
    1. Mongoose is a Node.js library that provides MongoDB object data mapping (ODM)
    2. Object Data Mapping (ODM) - similar to ORM where data from the database is converted automatically into a JavaScript object
    3. Must first have Node.js and MongoDB installed for code samples to work
    4. Install
      $ npm install --save mongoose
      
  2. Connecting to MongoDB
    1. Connect to a test database
      var mongoose = require('mongoose');
      
      var db = mongoose.connection;
      
      // Write any connection errors to console
      db.on('error', console.error);
      
      db.once('open', function() {
      	// Create schemas and models here
      });
      
      mongoose.connect('mongodb://localhost/test');
      
  3. Schemas and models
    1. Schema: defines the structure of documents within a MongoDB collection
    2. Model: used to create instances of data that will be stored in documents
    3. Schema for students database:
      var studentSchema = new mongoose.Schema({
      	name:      String,
      	gpa:       { type: Number, min: 0, max: 4 },
      	interests: [ String ],
      	enrolled:  Boolean
      });
      
      // Create a model from this schema and a MongoDB collection "Student"
      var Student = mongoose.model('Student', studentSchema);
      
    4. "Student" is capitalized because a constructor function is created which is used to create instances of the model which are docs that persist in MongoDB
    5. Nesting schemas
      var addressSchema = new mongoose.Schema({
      	street:    String,
      	city:      String,
      	zip:       Number
      });
      
      var studentSchema = new mongoose.Schema({
      	address:   addressSchema,
      	// etc...	
      });
      
  4. CRUD operations
    1. Create
      1. Create a single student
        var stu = new Student({
        	name: 'Sue Black',
        	gpa: '3.1',
        	interests: ["biking", "reading"],
        	enrolled: true
        });
        
        // Save Sue
        stu.save(function(err, stu) {
        	if (err) return console.error(err);
        	console.dir(stu);
        });
        
      2. Inserts student into database with unique ID
        { __v: 0,
          name: 'Sue Black',
          gpa: 3.1,
          enrolled: true,
          _id: 54bed326ee3562345840aa21,
          interests: [ 'biking', 'reading' ] }
        
    2. Read
      1. Read/query methods:
        1. Model.find(conditions, [fields], [options], [callback])
        2. Model.findById(id, [fields], [options], [callback])
        3. Model.findOne(conditions, [fields], [options], [callback])
      2. Find a single match
        // Find one 'Sue Black'
        Student.findOne({ name: 'Sue Black' }, function(err, stu) {
        	if (err) return console.error(err);
        	if (stu === null)
        		console.log('No student found');
        	else
        		console.dir(stu);
        });
        
        // Case-insensitive search using a regex
        var searchName = 'black';
        Student.findOne({ name: new RegExp(searchName, 'i') }, function(err, stu) {
        	if (err) return console.error(err);
        	if (stu === null)
        		console.log('No student found');
        	else 
        		console.dir(stu);
        });
        
      3. Find all
        // Find all students
        Student.find(function(err, students) {
        	if (err) return console.error(err);
        	console.dir(students);
        });
        
        // Find all students with gpa >= 3
        Student.find({ gpa: { $gte: 3 }}, function(err, students) {
        	if (err) return console.error(err);
        	console.dir(students);
        });
        
      4. Chaining queries (more)
        Student.find({ gpa: { $gte: 2 }})
        	.where('interests').in(['fishing', 'biking'])
        	.limit(5)
        	.sort({ 'gpa': 'desc' })
        	.exec(function(err, students) {
        		if (err) return console.error(err);
        		console.dir(students);
        	});
        
    3. Update
      1. Update methods:
        1. Model.update(conditions, update, [options], [callback])
        2. Model.findByIdAndUpdate(id, [update], [options], [callback])
        3. Model.findOneAndUpdate([conditions], [update], [options], [callback])
      2. Update single document
        // Change Sue's enrollment status
        Student.update({ name: 'Sue Black' }, { enrolled: false }, 
        	function(err, numAffected) {
        		if (err) return console.error(err);
        		console.log('Students updated: ' + numAffected);
        	});
        
      3. Update multiple documents
        // Add 0.5 to all GPAs <= 3.5
        Student.update({ gpa: { $lte: 3.5 } }, { $inc: { gpa: 0.5 } },
        	{ multi: true },
        	function(err, numAffected) {
        		if (err) return console.error(err);
        		console.log('Student GPAs updated: ' + numAffected);
        	});
        
    4. Delete
      1. Remove methods:
        1. Model.remove(conditions, [callback])
        2. Model.findByIdAndRemove(id, [options], [callback])
        3. Model.findOneAndRemove(conditions, [options], [callback])
      2. Remove by ID
        // Remove this one student 
        var id = '54c25ef804381320619c4ca9';   
        Student.findByIdAndRemove(id, function(err, stu) {
        	if (err) return console.error(err);
        	if (stu === null)
        		console.log('No student deleted');
        	else
        		console.log('Removed student ' + stu);
        });
        
      3. Remove all that match
        // Remove all students not enrolled 
        Student.remove({ enrolled: false }, function(err, numRemoved) {
        	if (err) return	console.error(err);
        	console.log('Students deleted: ' + numRemoved);
        });