Building Apps with MongoDB

Post on 08-Sep-2014

29.716 views 2 download

Tags:

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.

Transcript of Building Apps with MongoDB

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" : "bob@example.com", "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" : "bob@example.com" })

How do I...

Doing the “normal db” stuff

...change Bob’s email?db.posts.update(

{ "comments.email": "bob@example.com" },

{ $set : { "comments.$.email" : "robert@example.com" }})

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

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

MongoDB Language Centerhttp://www.mongodb.org/display/DOCS/Drivers

Development Trackerhttp://jira.mongodb.org

MongoDB Cookbookhttp://cookbook.mongodb.org/

Thanks!

{

email: “nate.abele@gmail.com”,

twitter: “@nateabele”,

web: “http://lithify.me/”,

slides: “http://www.slideshare.net/nateabele”

}