Upload
nate-abele
View
29.716
Download
2
Embed Size (px)
DESCRIPTION
Relational databases are central to web applications, but they have also been the primary source of pain when it comes to scale and performance. Recently, non-relational databases (also referred to as NoSQL) have arrived on the scene. This session explains not only what MongoDB is and how it works, but when and how to gain the most benefit.
Citation preview
Building Apps With
Nate Abele
IPC — 1 June 2010
Berlin
X
Me
Former lead developer, CakePHP
Lead developer, Lithium
Twitter: @nateabele
“Alternative” databases? What’s the point?
Relational databases » relational algebra » set theory
ORM “impedance mismatch”
Failed alternatives reinforced the status quo
What’s a document database?
Composed of documents ...duh
Each document is heterogenous, and may have a completely unique structure compared to other documents
...That’s pretty much it
Why Mongo?
.org :
“The best features of document databases,key-value stores, and relational databases.”
Mongo is...
Fast
Smart
Scalable
Terminology
Database » Database
Table » Collection
Row » Document
Common Tasks
postsidtitleslugbodypublishedcreatedupdated
commentsidpost_idauthoremailbodycreated
posts_tagsidpost_idtag_id
tagsidname
MySQL
Common Tasks
MongoDB
postsidtitleslugbodypublishedcreatedupdated
commentsauthoremailbodycreated
tags
Common TasksMongoDB
{ "_id" : ObjectId("4c03e856e258c2701930c091"), "title" : "Welcome to MongoDB", "slug" : "welcome-to-mongodb", "body" : "Today, we're gonna totally rock your world...", "published" : true, "created" : "Mon May 31 2010 12:48:22 GMT-0400 (EDT)", "updated" : "Mon May 31 2010 12:48:22 GMT-0400 (EDT)", "comments" : [ { "author" : "Bob", "email" : "[email protected]", "body" : "My mind has been totally blown!", "created" : "Mon May 31 2010 12:48:22 GMT-0400 (EDT)" } ], "tags" : [ "databases", "MongoDB", "awesome" ]}
[...frantic hand-wringing ensues...]
[...pause, deep breath...]
Doing the “normal db” stuff
...do pattern-matching?db.posts.find({ "title" : /mongodb/i })
...find all posts tagged ‘MongoDB’?db.posts.find({ "tags" : "MongoDB" })
...find all Bob’s comments?db.posts.find({ "comments.email" : "[email protected]" })
How do I...
Doing the “normal db” stuff
...change Bob’s email?db.posts.update(
{ "comments.email": "[email protected]" },
{ $set : { "comments.$.email" : "[email protected]" }})
How do I...
$set?
Querying$gt $all$gte $size$lt $exists $lte $type$ne $elemMatch $in $not$nin $where$mod
QueryingdontTrust = db.people.find({ “age”: { $gt : 30 }})
awesome = db.posts.find({ “tags” : { $in : [‘MongoDB’, ‘awesome’]}})
todo = db.tasks.find({ “status” : { $nin : [ ‘In Progress’, ‘Completed‘ ]}})
QueryingBy arbitrary function:db.posts.find({ $where: function() { return this.hits % 2 == 0;}})
By grouping key:db.posts.group({ "key": { "hits": true }, "initial": { count: 0 }, "reduce": function(obj, prev) { prev.count++; }});
QueryingBy grouping function:db.photos.group({ keyf: function(o) { return { hits: Math.round(o.hits / 1000) }; }, "initial": { count: 0 }, "reduce": function(obj, prev) { prev.count++; }});
Grouping results[ { 'hits' => 0, 'count' => 5 }, { 'hits' => 1, 'count' => 4 }, { 'hits' => 2, 'count' => 7 }, ...]
Map/reduce
...with apologies to John Nunemaker.
Map/reduce
> db.items.insert({tags: ['dog', 'cat']})> db.items.insert({tags: ['dog']})> db.items.insert({tags: ['dog', 'mouse']})> db.items.insert({tags: ['dog', 'mouse', 'hippo']})> db.items.insert({tags: ['dog', 'mouse', 'hippo']})> db.items.insert({tags: ['dog', 'hippo']})
Map/reduce
> var map = function() { this.tags.forEach(function(t) { emit(t, {count: 1}); });}
Map/reduce> var reduce = function(key, val) { var count = 0; for(var i = 0, len = val.length; i < len; i++) { count += val[i].count; } return { count: count };}
Map/reduce
> var result = db.items.mapReduce(map, reduce);
Map/reduce{ "ok" : 1, "timeMillis" : 86, "result" : "tmp.mr.mapreduce_1273861517_683", "counts" : { "input" : 6, "emit" : 13, "output" : 4 }}
Map/reduce
db["tmp.mr.mapreduce_1273861517_683"].find()
{ "_id" : "cat","value" : { "count" : 1 } } { "_id" : "dog","value" : { "count" : 6 } } { "_id" : "hippo", "value" : { "count" : 3 } } { "_id" : "mouse", "value" : { "count" : 3 } }
Atomic Operations
Incrementing & decrementing: $inc:
db.posts.update( { _id : new ObjectId("4c041e...30c093") }, { $inc : { "hits" : 1 }} )
db.posts.update( { _id : new ObjectId("4c041e...30c093") }, { $inc : { "hits" : -1 }} )
Atomic Operations
Adding, updating & removing: $set & $unset:
db.posts.update({}, { $set : { "hits" : 0 }})
db.posts.update({}, { $unset : { "hits" : 1 }})
Atomic Operations
Array operations: $push[All], $pull[All], $addToSet & $pop:
db.posts.update({ "tags": "MongoDB" }, { $push: { "tags" : "awesome" } })
db.posts.update({ "tags": "MySQL" }, { $pull: { "tags" : "awesome" } })
Atomic Operations
Array operations: $push[All], $pull[All], $addToSet & $pop:
db.queues.update( { _id : new ObjectId("4c041e...30c093") }, { $pop: { "operations" : 1 }} )
db.todos.update( { _id : new ObjectId("4c041e...30c093") }, { $pop: { "listItems" : -1 }} )
Indexes
Slows write performance, but greatly improves reads
For best results, index on what you query on
Mongo likes to fit its indexes in memory
Indexes
db.users.ensureIndex({ “email”: 1 })
db.posts.ensureIndex({ “tags”: 1 })
db.posts.ensureIndex({ “created”: -1 })
db.posts.ensureIndex({ “tags”: 1, “created”: -1})
Indexes
“unique” / “dropDups”: ensure uniqueness
“safe”: Make sure it worked. Else, panic.
“name”: Mostly for troubleshooting
“background”: Best. Performance. Panic. Button. Ever.
IndexesWhen in doubt, explain()
{ "cursor" : "BtreeCursor hits_1 multi", "indexBounds" : [ [{ "hits" : 0 }, { "hits" : 0 }], [{ "hits" : 1 }, { "hits" : 1 }] ], "nscanned" : 1, "nscannedObjects" : 1, "n" : 1, "millis" : 35, "allPlans" : [ { "cursor" : "BtreeCursor hits_1 multi", "indexBounds" : [ [{ "hits" : 0 }, { "hits" : 0 }], [{ "hits" : 1 }, { "hits" : 1 }] ] } ]}
Location, location, location
Location
MongoDB makes location-aware apps stupid-simple
First, add an index:
db.places.ensureIndex({ location: “2d” })
Go to town:
db.places.find({ location: { $near : [ 40.79870933724115, -73.7656099560547 ]}})
Location
Location
db.places.find({ location: { $within : { $box : { [ [40.800788494123154, -73.85556051757814], [40.68008976560161, -74.04232809570314] ]});
Easy to get startedUp and running on most systems in a half-dozen commands or less fewer
http://try.mongodb.org/
Coming to a platform near you
Drupal for MongoDBhttp://drupal.org/project/mongodb
D7: mongodb_cache: Store cache items in mongodb
D7: mongodb_field_storage: Store the fields in mongodb
D7: mongodb_session: Store sessions in mongodb
D6/D7: mongodb_watchdog: Store the watchdog messages in mongodb
D6/D7: mongodb: support library for the other modules
D7: mongodb_block: Store block information in mongodb. Very close to the core block API
D7: mongodb_queue: DrupalQueueInterface implementation using mongodb
http://sf2010.drupal.org/conference/sessions/mongodb-humongous-drupal
Even MORE Drupal
Work to get listing API into core:http://drupal.org/node/780154
Experimental goodies to play with:http://drupalcode.org/viewvc/drupal/contributions/sandbox/chx/dbtng_mongo_experimental/
Joomla!
MongoDB helper library for Joomla!
Branch of 1.6 development for alternative query builder
Full MongoDB support most likely in 2.0
Lithium PHP framework
MongoDB native support since 0.2
http://rad-dev.org/lithium/wiki
Projects demonstrating MongoDB support:
http://rad-dev.org/lithium_mongo/source
http://rad-dev.org/lithium_blog/source
CakePHP framework
MongoDB datasourcehttp://github.com/ichikaway/mongoDB-Datasource
Example articlehttp://mark-story.com/posts/view/using-mongodb-with-cakephp
MongoDB Language Centerhttp://www.mongodb.org/display/DOCS/Drivers
Community Resourceshttp://www.mongodb.org/display/DOCS/Community
MongoDB Cookbookhttp://cookbook.mongodb.org/
Thanks!
{
email: “[email protected]”,
twitter: “@nateabele”,
web: “http://lithify.me/”,
slides: “http://www.slideshare.net/nateabele”
}