mongoose and mongodb 101
DESCRIPTION
Slides from November Phoenix MongoDB User GroupTRANSCRIPT
MongoDB and Mongoose 101
Phoenix MongoDB MeetupNovember 16, 2013
Will Button @wfbutton
About Me
• DevOps/IT/DBA for myList.com
• Founder of FitMeal.me – Meal Planning
• Extensive background in both development and ops, specifically in scalability and sustainability
MongoDB – The 10,000 foot View
Assumptions:• You know it’s a database• You know it’s NoSQL• You either have it installed or• You’re sitti ng next to someone who does
SQL to Mongo Terminology
In SQL
• Database
• Table
• Record
In Mongo
• Database
• Collection
• Document
Basic CRUD Operations
Our dataset:
Users:
firstName:{type:String}, lastName:{type:String}, userName:{type:String, unique: true}, password:{type:String}, avatar:{type:String}, position:{type:String}
Basic CRUD Operations
Wills-MacBook-Pro:~ willbutton$ mongoMongoDB shell version: 2.2.0connecting to: test> use myappswitched to db myapp>
Basic CRUD Operations
> db.users.insert( { firstName: "Will", lastName: "Button", username: "rekibnikufesin", password: "Password", avatar: "images/will.png", position: "CEO" } )>
“C” is for Create
Basic CRUD Operations
> db.users.find(){ "_id" : ObjectId("5282dbceca316975c21907ef"), "firstName" : "Will", "lastName" : "Button", "username" : "rekibnikufesin", "password" : "Password", "avatar" : "images/will.png", "position" : "CEO" }> db.users.findOne(){
"_id" : ObjectId("5282dbceca316975c21907ef"),"firstName" : "Will","lastName" : "Button","username" : "rekibnikufesin","password" : "Password","avatar" : "images/will.png","position" : "CEO"
} > db.users.find( { firstName: "Will" } ){ "_id" : ObjectId("5282dbceca316975c21907ef"), "firstName" : "Will", "lastName" : "Button", "username" : "rekibnikufesin", "password" : "Password", "avatar" : "images/will.png", "position" : "CEO" }>
“R” is for Read
Basic CRUD Operations
> db.users.update( { firstName: "Will", lastName: "Button" }, { $set: { position: "Janitor" } } )> > db.users.find(){ "_id" : ObjectId("5282dbceca316975c21907ef"), "avatar" : "images/will.png", "firstName" : "Will", "lastName" : "Button", "password" : "Password", "position" : "Janitor", "username" : "rekibnikufesin" }>
“U” is for Update
$set is your friend!
Basic CRUD Operations
> db.users.remove( { lastName: "Button" } ) > db.users.count()0>
“D” is for Delete
mongoose
• MongoDB object modeling for node.js
?!@@?!#!@!
Why mongoose?
Let's face it, writing MongoDB validation, casting and business logic boilerplate is a drag. That's why we wrote Mongoose.
var mongoose = require('mongoose');mongoose.connect('mongodb://localhost/test');
var Cat = mongoose.model('Cat', { name: String });
var kitty = new Cat({ name: 'Zildjian' });kitty.save(function (err) { if (err) // ... console.log('meow');});Mongoose provides a straight-forward, schema-based solution to modeling your application data and includes built-in type casting, validation, query building, business logic hooks and more, out of the box.
Go With The Flow:
Collections Schema
Model
DocumentsDocuments
Putting it in action:
Use case:• Build a CRM application using the M.E.A.N. stack• Using Mongoose, provide basic CRUD operations inside the node stack
Database Schema
Database:myapp
Collection:users
Collection:documents
Collection:communications
firstNamelastNameusernamepasswordavatarposition
docOwnerdocTypedateSaveddescriptionfileLocation
commTypedatedescriptionfollowUpDatecontact
SchemaA schema maps to a MongoDB collection and defines the shape of the documents within that collection
var userSchema = new mongoose.Schema({
firstName:{type:String}, lastName:{type:String}, userName:{type:String, unique: true}, password:{type:String}, avatar:{type:String}, position:{type:String}
})
ModelsTo use our schema definition, we need to convert our blogSchema into a Model we can work with
app.db.model('user',userSchema) ;
DocumentsInstances of Models are Documents
var user = req.app.db.model('user') ;
Documents have built-in methods:
var query = user.find() ; query.sort({lastName:'asc'}) ; query.exec(function(err,data){ if(err){ console.log(err); res.send(500) ; } res.json(data) ; })
Putting it all together
Open a connection
app.db = mongoose.createConnection('mongodb://localhost/myapp') ;
app.db.on('error', function() { console.error.bind(console, 'mongoose connection error: ');});app.db.once('open', function () { console.log('mongoose open for business');});
routes.js
api/users.js
routes.js
api/users.js
Badass, Right?
But that only gets us so far.Let’s explore some of the other features available to us, such as validations, sub-documents, populations
Queries var user = req.app.db.model('user') ;
try{ var id = req.params['userId'] ; user.findOne({_id: id}, 'firstName userName', function(err,data){ console.log('find by id') ; res.json(data) ; }); } catch(e){ console.log(e); res.send(e) ; }
var user = req.app.db.model('user'); // console.log(req.body) ; var newuser = new user(req.body); newuser.validate(function(error) { if (error) { res.json({ error : error }); } else { delete req.body._id ; user.findByIdAndUpdate({_id:newuser._id},{$set:req.body},function(err,data){ res.json(data) ; })
} });
ValidationsValidation is defined in the SchemaTypeValidation occurs when a document attempts to be saved, after defaults have been appliedValidation is asynchronously recursive; when you call Model#save, sub-document validation is executed as well
All SchemaTypes have the built in required validator.Numbers have min and max validators.Strings have enum and match validators.
var user = req.app.db.model('user'); // console.log(req.body) ; var newuser = new user(req.body); newuser.validate(function(error) { if (error) { res.json({ error : error }); } else { delete req.body._id ; user.findByIdAndUpdate({_id:newuser._id},{$set:req.body},function(err,data){ res.json(data) ; })
} });
Validations
var userSchema = new mongoose.Schema({
firstName:{type:String}, lastName:{type:String}, userName:{type:String, unique: true}, password:{type:String}, avatar:{type:String}, position:{type:String}
})
Sub-DocumentsDocuments within documents?!?!? What is this witchcraft you speak of???
Sub-documents are documents with their own schema and are elements of a parent’s document array
• All the same features as normal documents• Saved when parent document saved• Errors bubble up to parent callback
Sub-Documentsvar childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({ children: [childSchema]})
Finding a sub-documentvar doc = parent.children.id(id);
parent.children.push({ name: 'Liesl' });
Add with standard array methods: push, addToSet, unshift
Remove by idvar doc = parent.children.id(id).remove();
PopulationAllows “joining” data from other collectionsvar communicationSchema = new mongoose.Schema({ commType:{type:String}, date:{type:Date}, description:{type:String}, followUpDate:{type:Date}, owner:[{type: mongoose.Schema.Types.ObjectId, ref:'user'}] })
var userSchema = new mongoose.Schema({
firstName:{type:String}, lastName:{type:String}, userName:{type:String, unique: true}, password:{type:String}, avatar:{type:String}, position:{type:String}
})
var Communication= mongoose.model(’Comm', communicationSchema);var User= mongoose.model(’User', userSchema);
Populationvar stevie = new User({ _id: 0, firstName: “Stevie”, lastName: “Wonder” })
stevie.save(function (err){ if (err) return handleError(err);
var comm1 = new Communication({ commType: “Phone call”, description: “I just called to say I love you”, owner: stevie._id });
comm1.save(function (err){ if (err) return handleError(err); });})
Communication .findOne({ commType: “Phone call”}).populate(‘owner’).exec(function (err,comm){
if(err) return handleError(err);console.log(‘Call owner is %s’, communication.owner.firstName);
})
Thank You!
• Questions• Comments• More Info