OSCON 2012 MongoDB Tutorial

53,584 views
52,188 views

Published on

This tutorial will introduce the features of MongoDB by building a simple location-based application using MongoDB. The tutorial will cover the basics of MongoDB’s document model, query language, map-reduce framework and deployment architecture.

The tutorial will be divided into 5 sections:

Data modeling with MongoDB: documents, collections and databases
Querying your data: simple queries, geospatial queries, and text-searching
Writes and updates: using MongoDB’s atomic update modifiers
Trending and analytics: Using mapreduce and MongoDB’s aggregation framework
Deploying the sample application
Besides the knowledge to start building their own applications with MongoDB, attendees will finish the session with a working application they use to check into locations around Portland from any HTML5 enabled phone!

TUTORIAL PREREQUISITES
Each attendee should have a running version of MongoDB. Preferably the latest unstable release 2.1.x, but any install after 2.0 should be fine. You can dowload MongoDB at http://www.mongodb.org/downloads.

Instructions for installing MongoDB are at http://docs.mongodb.org/manual/installation/.

Additionally we will be building an app in Ruby. Ruby 1.9.3+ is required for this. The current latest version of ruby is 1.9.3-p194.

For windows download the http://rubyinstaller.org/
For OSX download http://unfiniti.com/software/mac/jewelrybox/
For linux most users should know how to for their own distributions.
We will be using the following GEMs and they MUST BE installed ahead of time so you can be ahead of the game and safe in the event that the Internet isn’t accommodating.

bson (1.6.4)
bson_ext (1.6.4)
haml (3.1.4)
mongo (1.6.4)
rack (1.4.1)
rack-protection (1.2.0)
rack shotgun (0.9)
sinatra (1.3.2)
tilt (1.3.3)
Prior ruby experience isn’t required for this. We will NOT be using rails for this app.

Published in: Technology
7 Comments
61 Likes
Statistics
Notes
No Downloads
Views
Total views
53,584
On SlideShare
0
From Embeds
0
Number of Embeds
16
Actions
Shares
0
Downloads
1,066
Comments
7
Likes
61
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Intel's improved microprocessor chip is introduced April 1, 1974, the 8080 becomes a standard in the computer industry.\n\nThis predates Microsoft, Apple \n
  • Remember in 1995 there were around 10,000 websites. Mosiac, Lynx, Mozilla (pre netscape) and IE 2.0 were the only web browsers. \nApache (Dec ’95), Java (’96), PHP (June ’95), and .net didn’t exist yet. Linux just barely (1.0 in ’94)\n
  • Remember in 1995 there were around 10,000 websites. Mosiac, Lynx, Mozilla (pre netscape) and IE 2.0 were the only web browsers. \nApache (Dec ’95), Java (’96), PHP (June ’95), and .net didn’t exist yet. Linux just barely (1.0 in ’94)\n
  • Remember in 1995 there were around 10,000 websites. Mosiac, Lynx, Mozilla (pre netscape) and IE 2.0 were the only web browsers. \nApache (Dec ’95), Java (’96), PHP (June ’95), and .net didn’t exist yet. Linux just barely (1.0 in ’94)\n
  • \n
  • \n
  • Galaxy III released in May\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • By reducing transactional semantics the db provides, one can still solve an interesting set of problems where performance is very important, and horizontal scaling then becomes easier.\n\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • After this I’ll jump to my terminal and demo a few things.\n
  • wget http://c.spf13.com/OSCON/venuesImport.json\nmongoimport -d milieu -c venues venuesImport.json\n\n
  • After this I’ll jump to my terminal and demo a few things.\n
  • After this I’ll jump to my terminal and demo a few things.\n
  • After this I’ll jump to my terminal and demo a few things.\n
  • After this I’ll jump to my terminal and demo a few things.\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • OSCON 2012 MongoDB Tutorial

    1. MongoDB
    2. Today’s AgendaMongoDB IntroMongoDB FundamentalsRunning MongoDBBuilding your first appDeploying your first app to Heroku
    3. @spf13 AKASteve Francia15+ years buildingthe internet Father, husband, skateboarderChief Solutions Architect @responsible for drivers,integrations, web & docs
    4. Company behind MongoDBHQ in NYC & Palo Alto,Offices in Sydney, London & DublinSupport, consulting, training
    5. Introduction toMongoD
    6. A bit ofhistory
    7. 1974The relational database is created
    8. 1979
    9. 1979 1994
    10. 1979 1994 1995
    11. Computers in 1995100 mhz Pentium10 base T16 MB ram200 MB HD
    12. Cloud in 1995(Windows 95 cloud wallpaper)
    13. Cell Phones inQuad core 1.4Ghz802.11n (300+ Mbps)2 GB ram64 GB Solid State
    14. The world is vastlydifferent than theone the relational database was created for
    15. What do we want in an ideal world?
    16. What do we want in an ideal world?
    17. What do we want in an ideal world?•Horizontal scaling •cloud compatible •works with standard servers
    18. What do we want in an ideal world?•Horizontal scaling •cloud compatible •works with standard servers•Fast
    19. What do we want in an ideal world?•Horizontal scaling •cloud compatible •works with standard servers•Fast•Easy Development •Features •The Right Data Model •Schema Agility
    20. MongoDB philosophy Keep functionality when we can (key/value stores are great, but we need more) Non-relational (no joins) makes scaling horizontally practical Document data models are good Database technology should run anywhere virtualized, cloud, metal, etc
    21. Under the hoodWritten in C++Runs nearly everywhereData serialized to BSONExtensive use of memory-mapped filesi.e. read-through write-throughmemory caching.
    22. DatabaseScalability & Performance Memcached MongoDB RDBMS Depth of Functionality
    23. “MongoDB has the bestfeatures of key/valuestores, documentdatabases andrelational databasesin one. John Nunemaker
    24. Relational made normalized data look like this Category • Name • Url Article User • Name Tag • Name • Slug • Name • Email Address • Publish date • Url • Text Comment • Comment • Date • Author
    25. Document databases makenormalized data look like this Article • Name • Slug • Publish date User • Text • Name • Author • Email Address Comment[] • Comment • Date • Author Tag[] • Value Category[] • Value
    26. But we’ve been usinga relational database for 40 years!
    27. How do people storedocuments in real life?
    28. Think about adoctors office There’s two ways theycould organize their files
    29. Each document type in it’s own drawerMRIs X-rays Lab Invoices Index 1 1 1 1 1 1 1 1 History Medications Lab Forms
    30. Each document type in it’s own drawerMRIs X-rays Lab Invoices Index 1 1 1 1 1 1 1 1 History Medications Lab Forms
    31. Each document type in it’s own drawerMRIs X-rays Lab Invoices Index 1 1 1 1 1 1 1 1 History Medications Lab Forms
    32. Group related records Patient 1 Patient 2 Patient 3 ... Vendor 1 Vendor 2 Vendor 3
    33. Group related records Patient 1 Patient 3 ... Patient 2 Vendor 1 Vendor 2 Vendor 3
    34. Databases work the same way Relation Docum Patient 1 Vendor 1 Article Category • Name • Name • Slug • Url • Publish User date • Text • Name • Author • Email Address Article User Tag • Name Comment[]• Name • Name• Email • Slug • Url • Comment Address • Publish date • Date • Author Comment Tag[] • Comment • Value • Date • Author Category[] • Value
    35. Terminology RDBMS MongoTable, View ➜ CollectionRow ➜ DocumentIndex ➜ IndexJoin ➜ EmbeddedForeign Key ➜ Document ReferencePartition ➜ Shard
    36. MongoDBUse Cases
    37. CMS / BlogNeeds:• Business needed modern data store for rapid development and scaleSolution:• Use PHP & MongoDBResults:• Real time statistics• All data, images, etc stored together easy access, easy deployment, easy high availability• No need for complex migrations• Enabled very rapid development and growth
    38. Photo Meta-Problem:• Business needed more flexibility than Oracle could deliverSolution:• Use MongoDB instead of OracleResults:• Developed application in one sprint cycle• 500% cost reduction compared to Oracle• 900% performance improvement compared to Oracle
    39. Customer AnalyticsProblem:• Deal with massive data volume across all customer sitesSolution:• Use MongoDB to replace Google Analytics / Omniture optionsResults:• Less than one week to build prototype and prove business case• Rapid deployment of new features
    40. ArchivingWhy MongoDB:• Existing application built on MySQL• Lots of friction with RDBMS based archive storage• Needed more scalable archive storage backendSolution:• Keep MySQL for active data (100mil)• MongoDB for archive (2+ billion)Results:• No more alter table statements taking over 2 months to run• Sharding fixed vertical scale problem• Very happily looking at other places to use MongoDB
    41. OnlineProblem:• MySQL could not scale to handle their 5B+ documentsSolution:• Switched from MySQL to MongoDBResults:• Massive simplification of code base• Eliminated need for external caching system• 20x performance improvement over MySQL
    42. E-commerceProblem:• Multi-vertical E-commerce impossible to model (efficiently) in RDBMSSolution:• Switched from MySQL to MongoDBResults:• Massive simplification of code base• Rapidly build, halving time to market (and cost)• Eliminated need for external caching system• 50x+ performance improvement over MySQL
    43. Tons more MongoDB casts a wide net people keep coming up with new and brilliant ways to use it
    44. In Good and 1000s more
    45. MongoD B
    46. Start with an (or array, hash, dict, eplace1 = { name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", tags : [ "business", "awesome" ]}
    47. Inserting the record Initial Data Load > db.places.insert(place1)> db.places.insert(place1)
    48. Querying> db.places.findOne({ zip: "10011", tags: "awesome" })> db.places.find({tags: "business" }){ name : "10gen HQ", address : "134 5th Avenue 3rd Floor", city : "New York", zip : "10011", tags : [ "business", "awesome" ]}
    49. Nested Documents{ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", tags : [ "business", "awesome" ], comments : [ { author : "Fred", date : "Sat Apr 25 2010 20:51:03", text : "Best Place Ever!" }]}
    50. Object ID> db.places.insert(place1)object(MongoId)#4 (1) { ["$id"]=> string(24) "4e9cc76a4a1817fd21000000"} 4e9cc76a4a1817fd21000000 |------||----||--||----| ts mac pid inc
    51. Updating> db.places.update( {name : "10gen HQ"}, { $push : { comments : { author : "steve", date : 6/26/2012, text : "Office hours are great!" } } })
    52. Atomic$set $unset $rename $push $pop $pull $addToSet $in
    53. Index nested documents// Index nested documents> db.posts.ensureIndex({ "comments.author":1 })> db.posts.find({comments.author:Fred}){ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", comments : [ { author : "Fred", date : "Sat Apr 25 2010 20:51:03", text : "Best Place Ever!" }]}
    54. Regular Expressions// Regular Expressions> db.posts.find({comments.author: /^Fr/}){ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", comments : [ { author : "Fred", date : "Sat Apr 25 2010 20:51:03", text : "Best Place Ever!" }]}
    55. Index multiple values// Index on tags (multi-key index)> db.posts.ensureIndex({ tags: 1})> db.posts.find( { tags: tech } ){ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", tags : [ "business", "awesome", "tech" ],}
    56. Geospatial// geospatial index> db.posts.ensureIndex({ "location": "2d" })> db.posts.find({"location":{$near:[22,42]}}){ _id : ObjectId("4c4ba5c0672c685e5e8aabf3"), name : "10gen HQ", address : "578 Broadway 7th Floor", city : "New York", zip : "10011", location : [ 22, 42 ],}
    57. Cursors$cursor = $c->find(array("foo" => "bar"));foreach ($cursor as $id => $value) { echo "$id: "; var_dump( $value );}$a = iterator_to_array($cursor);
    58. Pagingpage_num = 3;results_per_page = 10;cursor = db.collection.find() .sort({ "ts" : -1 }) .skip((page_num - 1) * results_per_page) .limit(results_per_page);
    59. RunningMongoDB
    60. Fire up a mongomongo mongod mongoexportmongoimport mongos mongostatmongo_console mongodump mongofilesmongorestore mongosniff mongotop
    61. Start Mongod mongod Note the dmongod --help for help and startup optionsThu Jul 12 23:19:49 [initandlisten] MongoDB starting : pid=32237 port=27017 dbpath=/data/db/ 64-bit host=Steves-MacBook-Air.localThu Jul 12 23:19:49 [initandlisten] db version v2.0.6, pdfile version 4.5Thu Jul 12 23:19:49 [initandlisten] git version:e1c0cbc25863f6356aa4e31375add7bb49fb05bcThu Jul 12 23:19:49 [initandlisten] build info: Darwin erh2.10gen.cc 9.8.0 Darwin KernelVersion 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386BOOST_LIB_VERSION=1_40Thu Jul 12 23:19:49 [initandlisten] options: {}Thu Jul 12 23:19:49 [initandlisten] journal dir=/data/db/journalThu Jul 12 23:19:49 [initandlisten] recover : no journal files present, no recovery neededThu Jul 12 23:19:49 [websvr] admin web console waiting for connections on port 28017Thu Jul 12 23:19:49 [initandlisten] waiting for connections on port 27017
    62. Download & Import the venues curl -L http://j.mp/OSCONvenues | mongoimport -d milieu -c venues Database Collectionwget http://c.spf13.com/OSCON/venuesImport.jsonmongoimport -d milieu -c venues venuesImport.json
    63. Start the Mongo shell mongo> help Note no ddb.help() help on db methodsdb.mycoll.help() help on collection methodsrs.help() help on replica set methodshelp admin administrative helphelp connect connecting to a db helphelp keys key shortcutshelp misc misc things to knowhelp mr mapreduceshow dbs show database namesshow collections show collections in current databaseshow users show users in current databaseshow profile show most recent system.profile
    64. Let’s look at the venues> use milieu Databaseswitched to db milieu> db.venues.count()50
    65. Let’s look at the venues> db.venues.findOne(){ "_id" : ObjectId("4ff73cb568840767e50d4e9c"), "location" : { "address" : "777 NE ML King Blvd.", "cc" : "US", "city" : "Portland", "country" : "United States", "distance" : 18, "geo" : [ -122.66293287277222, 45.52829837051139 ], "postalCode" : "97232", "state" : "OR" },"name" : "Agent Reboot Portland","stats" : { "checkinsCount" : 0, "usersCount" : 0 }}
    66. Creating a Geo index> db.venues.ensureIndex({ location.geo : 2d})> db.venues.getIndexes()[ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "milieu.venues", "name" : "_id_" }, { "v" : 1, "key" : { "location.geo" : "2d" }, "ns" : "milieu.venues", "name" : "location.geo_" }]
    67. ChallengesCreate a new DB & CollectionInsert a new record into this collection ... with a nested fieldInsert another recordCreate an index (on a common field)Query on the field and confirm index usedUpdate multiple records
    68. Building aMongoDB app
    69. MongoDB DriversOfficial Support for 12 languagesCommunity drivers for tons moreDrivers connect to mongo serversDrivers translate BSON into native typesmongo shell is not a driver, but works likeone in some ways
    70. Building an app in Ruby?Had to pick a languageSinatra is very minimal and approachableWanted to focus on MongoDB interactionRuby gems are awesomeWorks well on Windows, OS X & LinuxSeemed like a good idea at the time
    71. A crashcourse inSinatra & Ruby
    72. 1st Ruby
    73. Everything is an object1.class # => Fixnuma.class # => String:z.class # => Symbolclass Foo # => ClassendFoo.class # => FooFoo.new.class
    74. Structuredef do_stuff(thing) Method thing.do_the_stuffendclass TheThing Class def do_the_stuff puts "Stuff was done!" endenddo_stuff(TheThing.new) Invocation
    75. Stringsname = World # => "World""Hello, #{name}" # => "Hello, World"Hello, #{name} # => "Hello, #{name}"
    76. Numbers1 + 1 # => 21 + 1.1 # => 2.16 * 7 # => 426 ** 7 # => 279936Math.sqrt(65536) # => 256.01.class # => Fixnum(2 ** 42).class # => Fixnum(2 ** 64).class # => Bignum1.1.class # => Float
    77. ArraysArray.new # => []Array.new(3) # => [nil, nil, nil][] # => []a = [1,2,3] # => [1, 2, 3]a[0] = one # => "one"a # => ["one", 2, 3]a[-1] # => 3a[1..2] # => [2, 3]
    78. HashesHash.new # => {}{} # => {}h = {1 => "one", 2 => "two"}h[1] # => "one"h["1"] # => nilh[:one] = "einz" # => "einz"h[:one] # => "einz"h.keys # => [1, 2, :one]h.values # => ["one", "two", "einz"]
    79. Variables & NamesCamelCased # Classes, moduleswith_underscores # methods, local variables@instance_variable@@class_variable$GLOBAL_VARIABLE
    80. Control Structures if condition # ... elsif other_condition # ... end unless condition # ... end while # ... end
    81. Sinatra is...not Railsnot a frameworka DSL for quickly creatingweb applications in Rubywith minimal effort
    82. Hello World # myapp.rbrequire sinatraget / do Hello world!end
    83. HTTP Actions In Sinatra, a route is an HTTP method paired with a URL-matching pattern.Each route is associated with a block:get / do .. show something ..endpost / do .. create something ..endput / do .. replace something ..enddelete / do .. annihilate something ..end
    84. Routes Routes are matched in the order they are defined. The first route that matches the request is invoked.Route patterns may include named parameters,accessible via the params hash:get /hello/:name do # matches "GET /hello/foo" and "GET /hello/bar" # params[:name] is foo or bar "Hello #{params[:name]}!"end#You can also access named parameters via block parameters:get /hello/:name do |n| "Hello #{n}!"end
    85. Splat Route patterns may also include splat (or wildcard) parameters, accessible via the params[:splat] array:get /say/*/to/* do # matches /say/hello/to/world params[:splat] # => ["hello", "world"]endget /download/*.* do # matches /download/path/to/file.xml params[:splat] # => ["path/to/file", "xml"]end
    86. Introducing the milieu app
    87. Start with a skeleton /Users/steve/Code/milieu/app/ layout.haml*▸ config/ login.haml*▸ helpers/ navbar.haml*▾ model/ register.haml* mongodb.rb user_dashboard.haml* mongoModule.rb user_profile.haml* user.rb venue.haml*▾ public/ venues.haml* ▸ bootstrap/ app.rb* ▾ css/ config.ru* styles.css* Gemfile* ▸ images/ Gemfile.lock*▾ views/ Rakefile* footer.haml* README* index.haml*
    88. Download & Install deps mkdir milieu cd milieu wget http://c.spf13.com/OSCON/gettingStarted.tgz tar zxvf gettingStarted.tgz cd app bundle installUsing bson (1.6.4)Using bson_ext (1.6.4)Using googlestaticmap (1.1.3)Using haml (3.1.4)Using mongo (1.6.4)Using rack (1.4.1)Using rack-protection (1.2.0)Using shotgun (0.9)Using tilt (1.3.3)Using sinatra (1.3.2)Using bundler (1.1.4)Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
    89. Run app shotgun== Shotgun/WEBrick on http://127.0.0.1:9393/[2012-07-14 11:37:34] INFO WEBrick 1.3.1[2012-07-14 11:37:34] INFO ruby 1.9.3 (2012-04-20) [x86_64-darwin11.4.0][2012-07-14 11:37:34] INFO WEBrick::HTTPServer#start: pid=42185port=9393
    90. Open Browser to localhost:9393
    91. Connecting to MongoDB model/mongodb.rbrequire mongorequire ./model/mongoModulerequire ./model/userCONNECTION = Mongo::Connection.new("localhost")DB = CONNECTION.db(milieu)USERS = DB[users]VENUES = DB[venues]CHECKINS = DB[checkins]
    92. Listing Venues app.rbget /venues do @venues = VENUES.find haml :venuesend
    93. Listing Venues.container .content views/venues.haml %h2 Venues %table.table.table-striped %thead %tr %th Name %th Address %th Longitude %th Latitude %tbody ~@venues.each do |venue| %tr %td %a{:href => /venue/ << venue[_id].to_s}= venue[name] %td= venue[location][address] ? venue[location][address] : &nbsp %td= venue[location][geo][0].round(2) %td= venue[location][geo][1].round(2)
    94. Listing Venues localhost:9393/venues
    95. Paginating Venues app.rbget /venues/?:page? do @page = params.fetch(page, 1).to_i pp = 10 @venues = VENUES.find.skip( ( @page - 1 ) * pp).limit(pp) @total_pages = (VENUES.count.to_i / pp).ceil haml :venuesend
    96. Listing Venues localhost:9393/venues
    97. Creating UsersUsers are a bit special in our appNot just dataSpecial considerations for securepassword handlingNot complicated on MongoDB side, butslightly complicated on Ruby side
    98. Creating Usersclass User model/user.rbattr_accessor :_id, :name, :email, :email_hash, :salt, :hashed_password, :collection,:updated_at def initialize self.collection = users end def password=(pass) self.salt = random_string(10) unless self.salt self.hashed_password = User.encrypt(pass, self.salt) end def save col = DB[self.collection] self.updated_at = Time.now col.save(self.to_hash) endend
    99. Creating Userspost /register do app.rb u = User.new u.email = params[:email] u.password = params[:password] u.name = params[:name] if u.save() flash("User created") session[:user] = User.auth( params["email"], params["password"]) redirect /user/ << session[:user].email.to_s << "/dashboard" else tmp = [] u.errors.each do |e| tmp << (e.join("<br/>")) end flash(tmp) redirect /create endend
    100. Logging inconfigure do app.rb enable :sessionsendbefore do unless session[:user] == nil @suser = session[:user] endendget /user/:email/dashboard do haml :user_dashboardend
    101. User Dashboard.container views/user_dashboard.haml .content .page-header -unless @suser == nil? %h2="Dashboard" %br %image{src: "http://www.gravatar.com/avatar/" <<@suser.email_hash.to_s << .png} %h3= @suser.name.to_s -else redirect / %small %a{href: "/user/" << @suser.email.to_s << "/profile"} profile .container#main-topic-nav
    102. Dashboard localhost:9393/dashboard
    103. Showing a Venue app.rbget /venue/:_id do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one( { :_id => object_id }) haml :venueend
    104. Showing a Venue .row-fluid views/venue.haml .span4 %h2= @venue[name].to_s %p =@venue[location][address].to_s %br= @venue[location][city].to_s + + @venue[location][state].to_s + + @venue[location][postalCode].to_s .span8 %image{:src => << gmap_url(@venue, {:height =>300, :width => 450}) }
    105. A Venue localhost:9393/venue/{id}
    106. Nearby Venues app.rbget /venue/:_id do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) @nearby_venues = VENUES.find( { :location.geo => { :$near => [ @venue[location][geo][0], @venue[location][geo][1]] } }).limit(4).skip(1) haml :venueend
    107. Listing Nearby Venues... views/venue.haml .row-fluid - @nearby_venues.each do |nearby| .span3 %h2 %a{:href => /venue/ + nearby[_id].to_s}=nearby[name].to_s %p =nearby[location][address].to_s %br= nearby[location][city].to_s + + nearby[location][state].to_s + + nearby[location][postalCode].to_s %a{:href => /venue/ + nearby[_id].to_s} %image{:src => << gmap_url(nearby, {:height =>150, :width => 150, :zoom => 17}) }
    108. Nearby Venues localhost:9393/venue/{id}
    109. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    110. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    111. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    112. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    113. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    114. Checking in app.rbget /venue/:_id/checkin do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS.find_and_modify(:query => { :_id => @suser._id}, :update => {:$inc => { "venues." << object_id.to_s => 1 } }, :new => 1) if user[venues][params[:_id]] == 1 VENUES.update({ :_id => @venue[_id]}, { :$inc => { :stats.usersCount => 1, :stats.checkinsCount => 1}}) else VENUES.update({ _id: @venue[_id]}, { :$inc => { :stats.checkinsCount => 1}}) end flash(Thanks for checking in) redirect /venue/ + params[:_id]end
    115. Checkin In views/venue.haml%p %a.btn.btn-primary.btn-large{:href => /venue/ + @venue[_id].to_s + /checkin} Check In Here%p =@venue[stats][usersCount].ceil.to_s + users have checked in here + @venue[stats][checkinsCount].ceil.to_s + times%p=user_times_at
    116. You’ve been here def user_times_at helpers/milieu.rb if logged_in? times = You have checked in here if !@user.venues.nil? && !@user.venues[params[:_id]].nil? times << @user.venues[params[:_id]].to_s else times << 0 end times << times else times = Please <a href=/login>login</a> to jointhem. end end
    117. A Venue localhost:9393/venue/{id}
    118. Deployingto Heroku
    119. Installing the Dependencies gem install herokuFetching: excon-0.14.3.gem (100%)Fetching: heroku-api-0.2.8.gem (100%)Fetching: netrc-0.7.5.gem (100%)Fetching: mime-types-1.19.gem (100%)Fetching: rest-client-1.6.7.gem (100%)Fetching: launchy-2.1.0.gem (100%)Fetching: rubyzip-0.9.9.gem (100%)Fetching: heroku-2.28.12.gem (100%)Successfully installed excon-0.14.3Successfully installed heroku-api-0.2.8Successfully installed netrc-0.7.5Successfully installed mime-types-1.19Successfully installed rest-client-1.6.7Successfully installed launchy-2.1.0Successfully installed rubyzip-0.9.9Successfully installed heroku-2.28.128 gems installed
    120. Signup for Heroku
    121. Create app on Heroku heroku create app_nameEnter your Heroku credentials.Email: Your_Email@Your_Domain.comPassword (typing will be hidden):Found the following SSH public keys:1) id_rsa.pubWhich would you like to use with your Heroku account? 1Uploading SSH public key /Users/steve/.ssh/id_rsa.pub... doneCreating milieu... done, stack is cedarhttp://milieu.herokuapp.com/ | git@heroku.com:milieu.gitGit remote heroku added
    122. Pushing to Heroku git push heroku masterWarning: Permanently added the RSA host key for IP address 50.19.85.132 to thelist of known hosts.Counting objects: 67, done.Delta compression using up to 4 threads.Compressing objects: 100% (65/65), done.Writing objects: 100% (67/67), 206.04 KiB, done.Total 67 (delta 9), reused 0 (delta 0)-----> Heroku receiving push-----> Removing .DS_Store files-----> Ruby/Rack app detected-----> Installing dependencies using Bundler version 1.2.0.pre Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment Fetching gem metadata from http://rubygems.org/....... Installing bson (1.6.4) Installing bson_ext (1.6.4) with native extensions Installing googlestaticmap (1.1.3) Installing haml (3.1.4)
    123. Fetching gem metadata from http://rubygems.org/.......Pushing to Heroku Installing bson (1.6.4) Installing bson_ext (1.6.4) with native extensions Installing googlestaticmap (1.1.3) Installing haml (3.1.4) Installing mongo (1.6.4) Installing rack (1.4.1) Installing rack-protection (1.2.0) Installing shotgun (0.9) Installing tilt (1.3.3) Installing sinatra (1.3.2) Using bundler (1.2.0.pre) Your bundle is complete! It was installed into ./vendor/bundle Cleaning up the bundler cache.-----> Writing config/database.yml to read from DATABASE_URL-----> Discovering process types Procfile declares types -> (none) Default types for Ruby/Rack -> console, rake, web-----> Compiled slug size is 1.4MB-----> Launching... done, v3 http://milieu.herokuapp.com deployed to HerokuTo git@heroku.com:milieu.git * [new branch] master -> master
    124. Adding MongoHQ/Lab heroku addons:add mongohqAdding mongohq to milieu... done, v4 (free)Use `heroku addons:docs mongohq` to view documentation
    125. Adjusting Connection model/mongodb.rbif ENV[RACK_ENV] == production db = URI.parse(ENV[MONGOHQ_URL]) db_name = db.path.gsub(/^//, ) DB = Mongo::Connection.new( db.host, db.port).db(db_name) DB.authenticate(db.user, db.password) unless (db.user.nil? || db.user.nil?)else DB = Mongo::Connection.new( "localhost", 27017).db(milieu)end
    126. Config MongoHQ/Lab heroku config=== Config Vars for milieuGEM_PATH: vendor/bundle/ruby/1.9.1LANG: en_US.UTF-8MONGOHQ_URL: mongodb://heroku:3vw...xv12@staff.mongohq.com:100XX/appXXPATH: bin:vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/binRACK_ENV: production Password Port Username Server DB
    127. Connecting to the shellmongo -u USER -p PASSWORD SERVER:PORT/DB_NAME
    128. Importing the Venues mongoimport -u heroku -p PASSWORD -h staff.mongohq.com --port PORT -d DB_NAME -c venues venuesImport.json
    129. Debugging heroku logs2012-07-14T03:24:31+00:00 app[web.1]: /app/vendor/bundle/ruby/1.9.1/gems/mongo-1.6.4/lib/mongo/connection.rb:420:in `connect: Failed to connect to a master node at localhost:27017 (Mongo::ConnectionFailure)2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/mongo-1.6.4/lib/mongo/connection.rb:594:in `setup2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/mongo-1.6.4/lib/mongo/connection.rb:130:in `initialize2012-07-14T03:24:31+00:00 app[web.1]: from /app/model/mongodb.rb:5:in `new2012-07-14T03:24:31+00:00 app[web.1]: from /app/model/mongodb.rb:5:in `<top (required)>2012-07-14T03:24:31+00:00 app[web.1]: from /app/app.rb:4:in `<top (required)>2012-07-14T03:24:31+00:00 app[web.1]: from /app/config.ru:6:in `require2012-07-14T03:24:31+00:00 app[web.1]: from /app/app.rb:4:in `require2012-07-14T03:24:31+00:00 app[web.1]: from /app/config.ru:6:in `block in <main>2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `instance_eval2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:51:in `initialize2012-07-14T03:24:31+00:00 app[web.1]: from /app/config.ru:1:in `new2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:40:in `eval2012-07-14T03:24:31+00:00 app[web.1]: from /app/config.ru:1:in `<main>2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/builder.rb:40:in `parse_file2012-07-14T03:24:31+00:00 app[web.1]: from /app/vendor/bundle/ruby/1.9.1/gems/rack-1.4.1/lib/rack/server.rb:200:in `app
    130. Deploying new versions git push herokuCounting objects: 7, done.Delta compression using up to 4 threads.Compressing objects: 100% (4/4), done.Writing objects: 100% (4/4), 424 bytes, done.Total 4 (delta 2), reused 0 (delta 0)-----> Heroku receiving push-----> Removing .DS_Store files-----> Ruby/Rack app detected-----> Installing dependencies using Bundler version 1.2.0.pre Running: bundle install --without development:test --path vendor/bundle --binstubs bin/ --deployment Using bson (1.6.4) Using bson_ext (1.6.4) Using googlestaticmap (1.1.3) Using haml (3.1.4) Using mongo (1.6.4) Using rack (1.4.1) Using rack-protection (1.2.0)
    131. Using googlestaticmap (1.1.3)Deploying new versions Using haml (3.1.4) Using mongo (1.6.4) Using rack (1.4.1) Using rack-protection (1.2.0) Using shotgun (0.9) Using tilt (1.3.3) Using sinatra (1.3.2) Using bundler (1.2.0.pre) Your bundle is complete! It was installed into ./vendor/bundle Cleaning up the bundler cache.-----> Writing config/database.yml to read from DATABASE_URL-----> Discovering process types Procfile declares types -> (none) Default types for Ruby/Rack -> console, rake, web-----> Compiled slug size is 1.4MB-----> Launching... done, v6 http://milieu.herokuapp.com deployed to HerokuTo git@heroku.com:milieu.git 9d5d688..ad894be master -> master
    132. Checkout your deployed app
    133. Next ?
    134. It’s all on
    135. Programmin g Challenge
    136. Some Ideas‣Createdifferentuser levels ‣Timestamped(admin) Checkins‣Createinterface ‣Amore completeto add venues dashboard with stats‣Connecttofoursquare ‣Badgesor Categories‣Login w/twitter
    137. One More Thing...
    138. http://spf13.com http://github.com/s @spf13Question download at mongodb.orgWe’re hiring!! Contact us at jobs@10gen.com

    ×