8. Overview of MongoDB
M on g oD B
{
_id: ObjectId(),
title: 'node and mongodb',
slug: 'node-and-mongodb',
body: '...',
published: true,
created: new Date('09/01/2011'),
updated: new Date('09/16/2011'),
comments: [
{
author: 'bob',
email: 'bob@bob.me',
body: '...',
created: new Date('09/17/2011')
}
],
tags: ['MongoDB', 'database']
}
9. Overview of MongoDB
Get c ollec t ion
MongoDB shell
posts = db.posts
NodeJS
var mongodb = require('mongodb');
var db = new Db('test', new Server(host, port, {}),
{native_parser:true});
db.open(function(err, db){
db.collection('posts', function(err, posts){
// use posts collection here
});
});
10. Overview of MongoDB
I n ser t
MongoDB shell
var doc = {title: 'test posts', ...};
posts.insert(doc);
NodeJS
posts.insert(doc, function(err, reply){
// error or done
});
11. Overview of MongoDB
Q u er y
MongoDB shell
posts.find({"comments.author", "bob"})
NodeJS
posts.find({"comments.author", "bob"}, function(err, cursor){
cursor.toArray(function(err, docs){
// found docs here
});
});
12. Overview of MongoDB
Q u er y op er at or
{<field>:{<operator>:<value>}}
db.things.find({j:{$in: [2,4,6]}});
$gt, $lt, $gte, $lte
$all, $exists
$mod, $ne
$in, $nin
$nor, $or, $and
$size, $type, …
13. Overview of MongoDB
Up d at e
MongoDB shell
posts.update({_id: doc.id}, {$inc: {votes: 1}})
NodeJS
posts.update({_id: doc.id}, {$inc: {votes: 1}}, function(err, count){
});
14. Overview of MongoDB
M od if ier op er at ion s
$set – set a particular value
$unset – delete a particular field (v1.3+)
$inc – increment a particular value by a certain amount
$push – append a value to an array
$pushAll – append several values to an array
$pull – remove a value(s) from an existing array
$pullAll – remove several value(s) from an existing array
$bit – bitwise operations
15. Overview of MongoDB
R em ove
MongoDB shell
posts.remove({author: 'bob'})
NodeJS
posts.remove({author: 'bob'}, function(err, reply){})
16. Overview of MongoDB
I n d ex
MongoDB shell
posts.ensureIndex({author:1})
posts.ensureIndex({slug: 1 }, {unique: true});
db.things.ensureIndex(
{firstname: 1, lastname: 1},
{unique: true, background:true});
NodeJS
posts.ensureIndex({author:1}, function(err, reply){})
posts.ensureIndex({slug: 1 }, {unique: true}, function(err, reply){});
db.things.ensureIndex(
{firstname: 1, lastname: 1},
{unique: true, background:true}, function(err, reply){});
17. Overview of MongoDB
Geosp at ial
{ loc : [ 50 , 30 ] } //SUGGESTED OPTION
{ loc : { x : 50 , y : 30 } }
{ loc : { foo : 50 , y : 30 } }
{ loc : { lon : 40.739037, lat: 73.992964 } }
db.places.ensureIndex( { loc : "2d" } )
db.places.find( { loc : { $near : [50,50] , $maxDistance : 5 } } )
box = [[40.73083, -73.99756], [40.741404, -73.988135]]
db.places.find({"loc" : {"$within" : {"$box" : box}}})
center = [50, 50]
radius = 10
db.places.find({"loc" : {"$within" : {"$center" : [center, radius]}}})
18. Overview of MongoDB
O p t im izat ion
Don’t create index for every field
Be careful about single-key indexes with low selectivity.
Only one index could be used per query.
Use compound-key index.
db.places.ensureIndex( { location : “2d” , category : 1 } );
db.places.find( { location : { $near : [50,50] }, category : ‘coffee’ } );
Use hint. Use explain. Use the profiler.
Pay attention to the read/write ratio of your application.
See docs for more information
19. Overview of MongoDB
Ag g r eg at ion
posts.count( {author: 'bob'} )
posts.distinct("author")
SQL group
select a,b,sum(c) csum from coll where active=1 group by a,b
MongoDB group
db.coll.group(
{key: { a:true, b:true },
cond: { active:1 },
reduce: function(obj, out) { out.csum += obj.c; },
initial: { csum: 0 }
});
20. Overview of MongoDB
M ap R ed u c e
map = function() {
for (var i in this.tags) {
emit(this.tags[i], 1);
}
}
reduce = function(key, values) {
var count = 0;
for (var i in values) {
count += current[i];
}
return count;
}
// 1.8+ must set out collection
db.posts.mapReduce(map, reduce, {out: 'tags_count'})
21. Overview of MongoDB
M ap R ed u c e
> db.tags_count.find()
{"_id" : "MongoDB", "value" : 4}
{"_id" : "Map/Reduce", "value" : 2}
{"_id" : "Recipe", "value" : 7}
{"_id" : "Group", "value" : 1}
22. Overview of MongoDB
Gr id F S
Upload image
var gridStore = new GridStore(db, filename, "w");
gridStore.open(function(err, gridStore) {
gridStore.write(imageData, function(err, gridStore) {
gridStore.close(function(err, result) {
console.log(result._id);
users.update({_id: userId}, {$set: {avatarId: result._id}});
});
});
});
HTML
<img src="http://asset.url/gridfs/{{ user.avatarId }}" />
Use nginx-gridfs
26. Nest ed c allb ac k s, an d n ot D R Y ?
var database = new mongo.Db('testdb', new mongo.Server('localhost',
27017));
database.open(function(err, db) {
if(err) return handle(err);
db.collection('user', function(err, collection) {
if(err) return handle(err);
collection.find({}, function(err, cursor) {
if(err) return handle(err);
cursor.toArray(function(err, users) {
if(err) return handle(err);
doSomething(users);
});
});
});
});
27. How t o exp or t c ollec t ion
var database = new mongo.Db('testdb', new mongo.Server('localhost',
27017));
database.open(function(err, db){
db.collection('posts', function(err, posts) {
// can't export here?
});
});
exports.posts = ?
28. How t o sh ar e c ollec t ion ob jec t
controllers/user.js
var database = new mongo.Db('testdb', new mongo.Server('localhost',
27017));
//...
database.open(function(err, db){
db.collection('user', function(err, userColl){
userColl.find({}, function(err, cursor){
if(err) return handle(err);
cursor.toArray(function(err, users){
res.render('/user.html', {users: users});
})
});
});
});
29. How t o sh ar e c ollec t ion ob jec t
controllers/book.js
var database = new mongo.Db('testdb', new mongo.Server('localhost',
27017));
//...
database.open(function(err, db){
db.collection('user', function(err, userColl){
userColl.findOne({_id: book.author_id}, function(err, author){
res.render('/book.html', {book: book, author: author});
});
});
});
31. How ab ou t t h is
config.js
exports.db = mongo.db('mongo://localhost:27017/testdb')
32. An d t h is
controllers/user.js
var db = require('../config').db;
db.collection('user').find({}).toArray(function(err, users){
if(err) return handle(err);
res.render('/user.html', {users: users});
});
33. An d t h is
controllers/book.js
var db = require('../config').db;
db.collection('user').findOne({_id, book.author_id}, function(err,
author){
if(err) return handle(err);
res.render('/book.html', {book: book, author: author});
});
35. Patterns of mongoskin
var mongoskin = require('mongoskin');
var db = mongoskin.db('mongo://localhost:27017/testdb');
db.bind('users');
db.bind('books');
db.users.find({}).limit(10).sort({name:-1}).toArray(function(err,
users){
});
db.books.update({_id: bookId}, {$inc: {votes: 1}}, function(err,
reply){
});
36. Patterns of mongoskin
Pr oxy all m et h od s
node-mongoskin
var skindb = mongoskin.db('mongo://localhost:27017/testdb')
function callback(err, reply){}
skindb.addUser('foo', 'bar', callback);
node-mongodb-native
var db = new mongodb.Db('testdb',
new mongodb.Server('localhost', 27017));
function callback(err, reply){}
db.open(function(err, db){
if(err) return callback(err);
db.addUser('foo', 'bar', callback);
});
37. Patterns of mongoskin
SkinClass hold all parameters to open it
var SkinDb = exports.SkinDb = function(db, username, password) {
this.db = db;
this.username = username;
this.password = password;
this.state = STATE_CLOSE;
this.emitter = new events.EventEmitter();
this._collections = {};
};
38. Patterns of mongoskin
Proxy all methods inside open
for (var name in Db.prototype) {
SkinDb.prototype[name] = function() {
var args = Array.prototype.slice.call(arguments);
this.open(function(err, db) {
if (err) {
return args[args.length - 1](err);//callback(err)
} else {
return Db.prototype[name].apply(db, args);
}
});
};
}
39. Patterns of mongoskin
Open only on c e (pseudo-code)
SkinDb.prototype.open = function(fn) {
switch (this.state) {
case STATE_OPEN:
return fn(null, this.db);
case STATE_OPENNING:
// if call 'open' method multi times before opened
return this.emitter.addListener('open', fn);
case STATE_CLOSE:
this.state = STATE_OPENNING;
var that = this;
this.db.open(function(err, db){
that.db = db;
fn(err, db);
that.state = STATE_OPEN;
that.emitter.emit('open', err, db);
});
}
40. }
};
Patterns of mongoskin
R et u r n s S k in Collec t ion
SkinDb.prototype.collection = function(name) {
var collection = this._collections[name];
if (!collection) {
this._collections[name] = collection = new SkinCollection(this,
name);
}
return collection;
};
41. Patterns of mongoskin
S k in Collec t ion
var SkinCollection = exports.SkinCollection = function(skinDb,
collectionName) {
this.skinDb = skinDb;
this.collectionName = collectionName;
this.collection;
this.state = STATE_CLOSE;
this.internalHint;
var that = this;
this.__defineGetter__('hint', function() { return this.internalHint;
});
this.__defineSetter__('hint', function(value) {
this.internalHint = value;
this.open(function(err, collection) {
collection.hint = value;
that.internalHint = collection.hint;
});
});
this.emitter = new events.EventEmitter();
}
42. }
Patterns of mongoskin
Pr oxy all m et h od s in sid e S k in Collec t ion . op en
for (var name in Collection.prototype) {
SkinCollection.prototype[name] = function() {
var args = Array.prototype.slice.call(arguments);
this.open(function(err, collection) {
if (err) {
args[args.length - 1](err);// callback(err)
} else {
Collection.prototype[name].apply(collection, args);
}
});
};
}
43. Patterns of mongoskin
S k in Collec t ion . op en
SkinCollection.prototype.open = function(callback) {
//...
var that = this;
this.skinDb.open(function(err, db){
db.collection(that.collectionName, function(err, collection){
this.nativeCollection = collection;
callback(err, collection);
}
});
}
44. Patterns of mongoskin
R et u r n s S k in Cu r sor if n o c allb ac k
SkinCollection.prototype.find = function() {
var args = Array.prototype.slice.call(arguments);
if (args.length > 0 && typeof(args[args.length - 1]) === 'function')
{
this._find.apply(this, args);
}else {
return new SkinCursor(null, this, args);
}
};
An d so d o w it h S k in Cu r sor
45. Patterns of mongoskin
Pat t er n s of m on g osk in
SkinClass contains all parameters to get NativeObject
Proxy all method inside callback of op en ( )
Make open() method cache result
Return SkinClass object to chain execution