SlideShare a Scribd company logo
Building your rst
MongoDB Acaon
Agda
Introduction to MongoDB
MongoDB Fundamentals
Running MongoDB
Schema Design
Ruby & Sinatra Crash Course
Building Our First App
@spf13Steve Francia
AKA
Chief Developer Advocate @
responsible for drivers,
integrations, web & docs
Iroducon to
mongodb
What Is MongoDB?
* Document
* Open source
* High performance
* Horizontally scalable
* Full featured
MongoDB is a ___________ database
* Not for .PDF & .DOC files
* A document is essentially an associative
array
* Document == JSON object
* Document == PHP Array
* Document == Python Dict
* Document == Ruby Hash
* etc
Documt Database
* MongoDB is an open source
project
* On GitHub
* Licensed under the AGPL
* Commercial licenses available
* Contributions welcome
Op Source
* Written in C++
* Extensive use of memory-mapped files
i.e. read-through write-through memory
caching.
* Runs nearly everywhere
* Data serialized as BSON (fast parsing)
* Full support for primary & secondary indexes
* Document model = less work
High Pfoance
Hozoal Scable
* Ad Hoc queries
* Real time aggregation
* Rich query capabilities
* Traditionally consistent
* Geospatial features
* Support for most programming languages
* Flexible schema
Full Ftured
Depth of Functionality
Scalability&Performance
Memcached
MongoDB
RDBMS
Database ndscape
tp://w.mongodb.org/downloads
What is a Record?
K → Value
* One-dimensional storage
* Single value is a blob
* Query on key only
* No schema
* Value cannot be updated, only
replaced
Key Blob
Raonal
* Two-dimensional storage
(tuples)
* Each field contains a single
value
* Query on any field
* Very structured schema (table)
* In-place updates
* Normalization process requires
many tables, joins, indexes, and
poor data locality
Primary
Key
Documt
* N-dimensional storage
* Each field can contain 0, 1,
many, or embedded values
* Query on any field & level
* Flexible schema
* Inline updates *
* Embedding related data has optimal data
locality, requires fewer indexes, has better
performance
_id
Running
Mongodb
MongoD
Mongo Shl
user = {
username: 'fred.jones',
first_name: 'fred',
last_name: 'jones',
}
Sta wh an object
(or ay, hash, dict, c)
> db.users.insert(user)
Inst e record
No collection creation needed
> db.users.findOne()
{
"_id" : ObjectId("50804d0bd94ccab2da652599"),
"username" : "fred.jones",
"first_name" : "fred",
"last_name" : "jones"
}
Quying for e us
* _id is the primary key in MongoDB
* Automatically indexed
* Automatically created as an
ObjectId if not provided
* Any unique immutable value could
be used
_id
* ObjectId is a special 12 byte
value
* Guaranteed to be unique across
your cluster
* ObjectId("50804d0bd94ccab2da652599")
|-------------||---------||-----||----------|
ts mac pid inc
ObjectId
Scha
Design
Tdaonal scha design
Focuses on data stoge
Documt scha design
Focuses on use
4 Building blocks
of Documt Design
exibi
* Choices for schema design
* Each record can have different fields
* Field names consistent for
programming
* Common structure can be enforced by
application
* Easy to evolve as needed
Ays
* Each field can be:
* Absent
* Set to null
* Set to a single value
* Set to an array of many values
* Query for any matching value
* Can be indexed and each value in the array
is in the index
beed Documts
* An acceptable value is a
document
* Nested documents provide
structure
* Query any field at any level
* Can be indexed
* Object in your model
* Associations with other entities
 Aßociaon
Referencing (Relational) Embedding (Document)
has_one embeds_one
belongs_to embedded_in
has_many embeds_many
has_and_belongs_to_many
MongoDB has both referencing and embedding for universal coverage
Excise 1:
Mod a busineß card
Busineß Card
Contacts
{
“_id”: 2,
“name”: “Steven Jobs”,
“title”: “VP, New Product
Development”,
“company”: “Apple Computer”,
“phone”: “408-996-1010”,
“address_id”: 1
}
Rcing
Addresses
{
“_id”: 1,
“street”: “10260 Bandley Dr”,
“city”: “Cupertino”,
“state”: “CA”,
“zip_code”: ”95014”,
“country”: “USA”
}
Contacts
{
“_id”: 2,
“name”: “Steven Jobs”,
“title”: “VP, New Product
Development”,
“company”: “Apple Computer”,
“address”: {
“street”: “10260 Bandley Dr”,
“city”: “Cupertino”,
“state”: “CA”,
“zip_code”: ”95014”,
“country”: “USA”
},
“phone”: “408-996-1010”
}
being
Excise 2:
Store a busineß card
Contacts
db.contacts.insert(
{
“_id”: 2,
“name”: “Steven Jobs”,
“title”: “VP, New Product
Development”,
“company”: “Apple Computer”,
“phone”: “408-996-1010”,
“address_id”: 1
}
)
Insng wh Rce
Addresses
db.addresses.insert(
{
“_id”: 1,
“street”: “10260 Bandley Dr”,
“city”: “Cupertino”,
“state”: “CA”,
“zip_code”: ”95014”,
“country”: “USA”
}
)
Excise 3:
Re a busineß card
Contacts
c = db.contacts.findOne(
{
“name”: “Steven Jobs”,
}
)
Quying wh Rce
Addresses
db.addresses.findOne(
{
“_id”: c.address_id,
“street”: “10260 Bandley Dr”,
“city”: “Cupertino”,
“state”: “CA”,
“zip_code”: ”95014”,
“country”: “USA”
}
)
Building a
MongoDB
Acaon
MongoDB has nave bindings
for nr allnguages
Official Support for 12 languages
Community drivers for tons more
Drivers connect to mongo servers
Drivers translate BSON into native types
mongo shell is not a driver, but works like
one in some ways
Installed using typical means (npm, pecl,
gem, pip)
MongoDB dvs
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Building an a in Ruby?
Had to pick a language
Sinatra is very minimal and approachable
Wanted to focus on MongoDB interaction
Ruby gems are awesome
Works well on Windows, OS X & Linux
Seemed like a good idea at the time
Ruby
Csh Course
hing is an object
1.class
'a'.class
:z.class
class Foo
end
Foo.class
Foo.new.class
# => Fixnum
# => String
# => Symbol
# => Class
# => Foo
Structure
Method
Class
Invocation
def do_stuff(thing)
thing.do_the_stuff
end
class TheThing
def do_the_stuff
puts "Stuff was done!"
end
end
do_stuff(TheThing.new)
Stngs
name = 'World' # => "World"
"Hello, #{name}" # => "Hello, World"
'Hello, #{name}' # => "Hello, #{name}"
Numbs
1 + 1 # => 2
1 + 1.1 # => 2.1
6 * 7 # => 42
6 ** 7 # => 279936
Math.sqrt(65536) # => 256.0
1.class # => Fixnum
(2 ** 42).class # => Fixnum
(2 ** 64).class # => Bignum
1.1.class # => Float
Ays
Array.new
Array.new(3)
[]
a = [1,2,3]
a[0] = 'one'
a
a[-1]
a[1..2]
# => []
# => [nil, nil, nil]
# => []
# => [1, 2, 3]
# => "one"
# => ["one", 2, 3]
# => 3
# => [2, 3]
Hashes
Hash.new
{}
h = {1 => "one", 2 => "two"}
h[1]
h["1"]
h[:one] = "einz"
h[:one]
h.keys
h.values
# => {}
# => {}
# => "one"
# => nil
# => "einz"
# => "einz"
# => [1, 2, :one]
# => ["one", "two", "einz"]
Vaables & Names
CamelCased # Classes, modules
with_underscores # methods, local variables
@instance_variable
@@class_variable
$GLOBAL_VARIABLE
Corol Structuresif condition
# ...
elsif other_condition
# ...
end
unless condition
# ...
end
while
# ...
end
Build your first MongoDB App in Ruby @ StrangeLoop 2013
Sinat is...
not Rails
not a framework
a DSL for quickly creating web
applications in Ruby with
minimal effort
Hlo World
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
TP Acons
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 ..
end
post '/' do
.. create something ..
end
put '/' do
.. replace something ..
end
delete '/' do
.. annihilate something ..
end
Roes
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
Spt
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"]
end
get '/download/*.*' do
# matches /download/path/to/file.xml
params[:splat] # => ["path/to/file", "xml"]
end
Building our
A in Ruby
Iroducing e mieu a
pre-popung
our database
Download & Impo e vues
curl -L http://j.mp/StrangeLoopVenues | 
mongoimport -d milieu -c venues
wget http://c.spf13.com/dl/StrangeLoopVenues.json
mongoimport -d milieu -c venues StrangeLoopVenues.json
Database
Collection
Mongo Shl
L’s lk at e vues
> use milieu
switched to db milieu
> db.venues.count()
50
Database
L’s lk at e vues
> db.venues.findOne()
{
"_id" : ObjectId("52335163695c9d31c2000001"),
"location" : {
"address" : "1820 Market St",
"distance" : 85,
"postalCode" : "63103",
"city" : "Saint Louis",
"state" : "MO",
"country" : "United States",
"cc" : "US",
"geo" : [
-90.20761747801353,
38.62893438211461
]
},
"name" : "St. Louis Union Station Hotel- A DoubleTree by Hilton",
"contact" : {
"phone" : "3146215262",
"formattedPhone" : "(314) 621-5262",
"url" : "http://www.stlunionstationhotel.com"
},
"stats" : {
"checkinsCount" : 0,
"usersCount" : 0
}
}
Crng 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_"
}
]
Skon
Sta wh a skon
/Users/steve/Code/milieu/app/
▸ config/
▸ helpers/
▾ model/
mongodb.rb
mongoModule.rb
user.rb
▾ public/
▸ bootstrap/
▾ css/
styles.css
▸ images/
▾ views/
footer.haml
index.haml
layout.haml
login.haml
navbar.haml
register.haml
user_dashboard.haml
user_profile.haml
venue.haml
venues.haml
app.rb
config.ru
Gemfile
Rakefile
README
Download & Install deps
mkdir milieu
cd milieu
wget http://c.spf13.com/dl/GettingStarted.tgz
tar zxvf GettingStarted.tgz
bundle install
Resolving dependencies...
Using bson (1.9.2)
Using bson_ext (1.9.2)
Using googlestaticmap (1.1.4)
Using tilt (1.4.1)
Using haml (4.0.3)
Using mongo (1.9.2)
Using rack (1.5.2)
Using rack-protection (1.5.0)
Using shotgun (0.9)
Using sinatra (1.4.3)
Using bundler (1.3.5)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is
installed.
Run a
shotgun
== Shotgun/WEBrick on http://127.0.0.1:9393/
[2013-09-13 21:25:43] INFO WEBrick 1.3.1
[2013-09-13 21:25:43] INFO ruby 2.0.0 (2013-06-27)
[x86_64-darwin12.3.0]
[2013-09-13 21:25:43] INFO WEBrick::HTTPServer#start:
pid=85344 port=9393
Op Brows to locaost:9393
Pri --- ror Scre
sng
Vues
Connecng to MongoDB
require 'mongo'
require './model/mongoModule'
require './model/user'
# Connection code goes here
CONNECTION = Mongo::Connection.new("localhost")
DB = CONNECTION.db('milieu')
# Alias to collections goes here
USERS = DB['users']
VENUES = DB['venues']
CHECKINS = DB['checkins']
model/mongodb.rb
sng Vues
get '/venues' do
# Code to list all venues goes here
@venues = VENUES.░░░░░
haml :venues
end
app.rb
sng Vues
get '/venues' do
# Code to list all venues goes here
@venues = VENUES.find
haml :venues
end
app.rb
sng Vues
.container
.content
%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)
views/venues.haml
sng Vueslocalhost:9393/venues
Paginang Vues
get '/venues/?:page?' do
@page = params.fetch('page', 1).to_i
pp = 10
@venues = VENUES.find.░░░░░(░░░░).░░░░(░░░)
@total_pages = (VENUES.░░░░░.to_i / pp).ceil
haml :venues
end
app.rb
# replaces the prior entry
Paginang Vues
get '/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 :venues
end
app.rb
# replaces the prior entry
.container
.content
%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)
=pager('/venues')
sng Vues
views/venues.haml
paging rough Vueslocalhost:9393/venues
Crng
Uss
Crng Uss
Users are a bit special in our app
Not just data
Special considerations for secure
password handling
Not complicated on MongoDB side, but
slightly complicated on Ruby side
Crng Uss
class User
attr_accessor :_id, :name, :email, :email_hash, :salt, :hashed_password,
:collection, :updated_at
def init_collection
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)
end
end
model/user.rb
Inherited from
MongoModule.rb
Crng Uss
post '/register' do
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'
end
end
app.rb
Loing in pa 1
configure do
enable :sessions
end
before do
unless session[:user] == nil
@suser = session[:user]
end
end
get '/user/:email/dashboard' do
haml :user_dashboard
end
app.rb
Loing in pa 2
post '/login' do
if session[:user] = User.auth(params["email"], params["password"])
flash("Login successful")
redirect "/user/" << session[:user].email << "/dashboard"
else
flash("Login failed - Try again")
redirect '/login'
end
end
app.rb
Loing in pa 3
def self.auth(email, pass)
u = USERS.find_one("email" => email.downcase)
return nil if u.nil?
return User.new(u) if User.encrypt(
pass, u['salt']) == u['hashed_password']
nil
end
user.rb
Us Dashboard
.container
.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
views/user_dashboard.haml
Dashboard
localhost:9393/dashboard
Viing
Uss
nding a us
get '/user/:email/profile' do
u = USERS.░░░░░(
░░░░░ => ░░░░░.░░░░░)
if u == nil
return haml :profile_missing
else
@user = User.new(u)
end
haml :user_profile
end
app.rb
nding a us
get '/user/:email/profile' do
u = USERS.find_one(
"email" => params[:email].downcase)
if u == nil
return haml :profile_missing
else
@user = User.new(u)
end
haml :user_profile
end
app.rb
Crng an INdex
> db.users.ensureIndex({email : 1})
> db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "milieu.users",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"email" : 1
},
"ns" : "milieu.users",
"name" : "email_1"
}
]
A Vue
Showing a Vue
get '/venue/:_id' do
object_id = ░░░░░░░░░░░░░░
@venue = ░░░░░░░░░░(
{ ░░░░ => object_id })
haml :venue
end
app.rb
Showing a Vue
get '/venue/:_id' do
object_id = BSON::ObjectId.from_string(params[:_id])
@venue = VENUES.find_one(
{ :_id => object_id })
haml :venue
end
app.rb
Showing a Vue
.row
.col-md-4
%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
.col-md-8
%image{:src => '' << gmap_url(@venue, {:height =>
300, :width => 450}) }
views/venue.haml
A Vue
localhost:9393/venue/{id}
Nrby
VueS
Nrby Vues
get '/venue/:_id' do
object_id =
BSON::ObjectId.from_string(params[:_id])
@venue = VENUES.find_one({ :_id => object_id })
@nearby_venues = ░░░░░.░░░░░(
{░░░░░ =>{░░░░░=>[ ░░░░░,░░░░░]}}
).░░░░░(4).░░░░░(1)
haml :venue
end
app.rb
Nrby Vues
get '/venue/:_id' do
object_id =
BSON::ObjectId.from_string(params[:_id])
@venue = VENUES.find_one({ :_id => object_id })
@nearby_venues = VENUES.find(
{ :'location.geo' =>
{ ░░░░░ => [ ░░░░░,░░░░░]
}
}).░░░░░(4).░░░░░(1)
haml :venue
end
app.rb
Nrby Vues
get '/venue/:_id' do
object_id =
BSON::ObjectId.from_string(params[:_id])
@venue = VENUES.find_one({ :_id => object_id })
@nearby_venues = VENUES.find(
{ :'location.geo' =>
{ ░░░░░ => [ ░░░░░,░░░░░]
}
}).limit(4).skip(1)
haml :venue
end
app.rb
Nrby Vues
get '/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 :venue
end
app.rb
...
.row
- @nearby_venues.each do |nearby|
.col-md-3
%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}) }
views/venue.haml
sng Nrby Vues
Nrby Vues
localhost:9393/venue/{id}
Checng IN
Checng in
get '/venue/:_id/checkin' do
object_id = BSON::ObjectId.from_string(params[:_id])
@venue = VENUES.find_one({ :_id => object_id })
user = USERS. ░░░░░_and_░░░░░(░░░░░)
if ░░░░░
░░░░░ ░░░░░ ░░░░░ ░░░░░
else
░░░░░ ░░░░░ ░░░░░ ░░░░░
end
flash('Thanks for checking in')
redirect '/venue/' + params[:_id]
end
app.rb
Checng in
get '/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 => ░░░░░,
:update => ░░░░░,
:new => 1)
if ░░░░░
░░░░░ ░░░░░ ░░░░░ ░░░░░
else
░░░░░ ░░░░░ ░░░░░ ░░░░░
end
flash('Thanks for checking in')
redirect '/venue/' + params[:_id]
end
app.rb
Checng in
get '/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 ░░░░░
░░░░░ ░░░░░ ░░░░░ ░░░░░
else
░░░░░ ░░░░░ ░░░░░ ░░░░░
end
flash('Thanks for checking in')
redirect '/venue/' + params[:_id]
end
app.rb
Checng in
get '/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(░░░░░)
else
VENUES.update(░░░░░)
end
flash('Thanks for checking in')
redirect '/venue/' + params[:_id]
end
app.rb
Checng in
get '/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
app.rb
You’ve be he
def user_times_at
if logged_in?
times = 'You have checked in here '
if !@suser.venues.nil? &&
!@suser.venues[params[:_id]].nil? times <<
@suser.venues[params[:_id]].to_s
else
times << '0'
end
times << ' times'
else
times = 'Please <a href='/login'>login</a> to
join them.'
end
end
helpers/milieu.rb
Checn In
%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
views/venue.haml
A Vue localhost:9393/venue/{id}
What we’ve led
* Model data for
MongoDB
* Use MongoDB tools
to import data
* Create records from
shell & ruby
* Update records
* Atomic updates
* Create an index
* Create a geo index
* Query for data by
matching
* GeoQueries
* Pagination
* Single Document
Transactions
* Some ruby, sinatra,
haml, etc
Next ?
’s on Ghub
Some Ids* Create interface to add venues
* Connect to foursquare
* Login w/twitter
* Badges or Categories
* Enable searching of venues
* Tips / Reviews
E IF YOU KED !
Questions?
http://spf13.com
http://github.com/spf13
@spf13
Build your first MongoDB App in Ruby @ StrangeLoop 2013

More Related Content

What's hot (20)

The emerging world of mongo db csp
The emerging world of mongo db csp
Carlos Sánchez Pérez
 
Back to Basics Webinar 2: Your First MongoDB Application
Back to Basics Webinar 2: Your First MongoDB Application
MongoDB
 
Practical Ruby Projects With Mongo Db
Practical Ruby Projects With Mongo Db
Alex Sharp
 
Webinar: Getting Started with MongoDB - Back to Basics
Webinar: Getting Started with MongoDB - Back to Basics
MongoDB
 
Mongo db queries
Mongo db queries
ssuser6d5faa
 
OSDC 2012 | Building a first application on MongoDB by Ross Lawley
OSDC 2012 | Building a first application on MongoDB by Ross Lawley
NETWAYS
 
Conceptos básicos. Seminario web 5: Introducción a Aggregation Framework
Conceptos básicos. Seminario web 5: Introducción a Aggregation Framework
MongoDB
 
Conceptos básicos. Seminario web 4: Indexación avanzada, índices de texto y g...
Conceptos básicos. Seminario web 4: Indexación avanzada, índices de texto y g...
MongoDB
 
Conceptos básicos. seminario web 3 : Diseño de esquema pensado para documentos
Conceptos básicos. seminario web 3 : Diseño de esquema pensado para documentos
MongoDB
 
Conceptos básicos. Seminario web 2: Su primera aplicación MongoDB
Conceptos básicos. Seminario web 2: Su primera aplicación MongoDB
MongoDB
 
Back to Basics Webinar 1: Introduction to NoSQL
Back to Basics Webinar 1: Introduction to NoSQL
MongoDB
 
Learn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDB
Marakana Inc.
 
Mongo-Drupal
Mongo-Drupal
Forest Mars
 
Beyond the Basics 2: Aggregation Framework
Beyond the Basics 2: Aggregation Framework
MongoDB
 
Back to Basics Webinar 5: Introduction to the Aggregation Framework
Back to Basics Webinar 5: Introduction to the Aggregation Framework
MongoDB
 
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
MongoDB
 
DrupalCon Chicago Practical MongoDB and Drupal
DrupalCon Chicago Practical MongoDB and Drupal
Doug Green
 
OSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB Tutorial
Steven Francia
 
Back to Basics Webinar 3: Schema Design Thinking in Documents
Back to Basics Webinar 3: Schema Design Thinking in Documents
MongoDB
 
Introduction to MongoDB
Introduction to MongoDB
Justin Smestad
 
Back to Basics Webinar 2: Your First MongoDB Application
Back to Basics Webinar 2: Your First MongoDB Application
MongoDB
 
Practical Ruby Projects With Mongo Db
Practical Ruby Projects With Mongo Db
Alex Sharp
 
Webinar: Getting Started with MongoDB - Back to Basics
Webinar: Getting Started with MongoDB - Back to Basics
MongoDB
 
OSDC 2012 | Building a first application on MongoDB by Ross Lawley
OSDC 2012 | Building a first application on MongoDB by Ross Lawley
NETWAYS
 
Conceptos básicos. Seminario web 5: Introducción a Aggregation Framework
Conceptos básicos. Seminario web 5: Introducción a Aggregation Framework
MongoDB
 
Conceptos básicos. Seminario web 4: Indexación avanzada, índices de texto y g...
Conceptos básicos. Seminario web 4: Indexación avanzada, índices de texto y g...
MongoDB
 
Conceptos básicos. seminario web 3 : Diseño de esquema pensado para documentos
Conceptos básicos. seminario web 3 : Diseño de esquema pensado para documentos
MongoDB
 
Conceptos básicos. Seminario web 2: Su primera aplicación MongoDB
Conceptos básicos. Seminario web 2: Su primera aplicación MongoDB
MongoDB
 
Back to Basics Webinar 1: Introduction to NoSQL
Back to Basics Webinar 1: Introduction to NoSQL
MongoDB
 
Learn Learn how to build your mobile back-end with MongoDB
Learn Learn how to build your mobile back-end with MongoDB
Marakana Inc.
 
Beyond the Basics 2: Aggregation Framework
Beyond the Basics 2: Aggregation Framework
MongoDB
 
Back to Basics Webinar 5: Introduction to the Aggregation Framework
Back to Basics Webinar 5: Introduction to the Aggregation Framework
MongoDB
 
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
Webinaire 2 de la série « Retour aux fondamentaux » : Votre première applicat...
MongoDB
 
DrupalCon Chicago Practical MongoDB and Drupal
DrupalCon Chicago Practical MongoDB and Drupal
Doug Green
 
OSCON 2012 MongoDB Tutorial
OSCON 2012 MongoDB Tutorial
Steven Francia
 
Back to Basics Webinar 3: Schema Design Thinking in Documents
Back to Basics Webinar 3: Schema Design Thinking in Documents
MongoDB
 
Introduction to MongoDB
Introduction to MongoDB
Justin Smestad
 

Viewers also liked (10)

Getting Started with Go
Getting Started with Go
Steven Francia
 
MongoDB Analytics: Learn Aggregation by Example - Exploratory Analytics and V...
MongoDB Analytics: Learn Aggregation by Example - Exploratory Analytics and V...
MongoDB
 
Big data for the rest of us
Big data for the rest of us
Steven Francia
 
Painless Data Storage with MongoDB & Go
Painless Data Storage with MongoDB & Go
Steven Francia
 
7 Common mistakes in Go and when to avoid them
7 Common mistakes in Go and when to avoid them
Steven Francia
 
7 Common Mistakes in Go (2015)
7 Common Mistakes in Go (2015)
Steven Francia
 
The Future of the Operating System - Keynote LinuxCon 2015
The Future of the Operating System - Keynote LinuxCon 2015
Steven Francia
 
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
Steven Francia
 
What every successful open source project needs
What every successful open source project needs
Steven Francia
 
Building Awesome CLI apps in Go
Building Awesome CLI apps in Go
Steven Francia
 
Getting Started with Go
Getting Started with Go
Steven Francia
 
MongoDB Analytics: Learn Aggregation by Example - Exploratory Analytics and V...
MongoDB Analytics: Learn Aggregation by Example - Exploratory Analytics and V...
MongoDB
 
Big data for the rest of us
Big data for the rest of us
Steven Francia
 
Painless Data Storage with MongoDB & Go
Painless Data Storage with MongoDB & Go
Steven Francia
 
7 Common mistakes in Go and when to avoid them
7 Common mistakes in Go and when to avoid them
Steven Francia
 
7 Common Mistakes in Go (2015)
7 Common Mistakes in Go (2015)
Steven Francia
 
The Future of the Operating System - Keynote LinuxCon 2015
The Future of the Operating System - Keynote LinuxCon 2015
Steven Francia
 
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
Go for Object Oriented Programmers or Object Oriented Programming without Obj...
Steven Francia
 
What every successful open source project needs
What every successful open source project needs
Steven Francia
 
Building Awesome CLI apps in Go
Building Awesome CLI apps in Go
Steven Francia
 
Ad

Similar to Build your first MongoDB App in Ruby @ StrangeLoop 2013 (20)

Mongo db basics
Mongo db basics
Claudio Montoya
 
Dev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDB
MongoDB
 
Webinar: Getting Started with Ruby and MongoDB
Webinar: Getting Started with Ruby and MongoDB
MongoDB
 
MongoDB at FrozenRails
MongoDB at FrozenRails
Mike Dirolf
 
Mongo db
Mongo db
Gyanendra Yadav
 
Building your first app with MongoDB
Building your first app with MongoDB
Norberto Leite
 
MongoDB
MongoDB
Rony Gregory
 
9. Document Oriented Databases
9. Document Oriented Databases
Fabio Fumarola
 
Mongo learning series
Mongo learning series
Prashanth Panduranga
 
MongoDB - Ruby document store that doesn't rhyme with ouch
MongoDB - Ruby document store that doesn't rhyme with ouch
Wynn Netherland
 
Introduction to MongoDB
Introduction to MongoDB
Mike Dirolf
 
Introduction to using MongoDB with Ruby
Introduction to using MongoDB with Ruby
Jonathan Holloway
 
Meetup#1: 10 reasons to fall in love with MongoDB
Meetup#1: 10 reasons to fall in love with MongoDB
Minsk MongoDB User Group
 
MongoDB: a gentle, friendly overview
MongoDB: a gentle, friendly overview
Antonio Pintus
 
MongoDB
MongoDB
wiTTyMinds1
 
MongoDB NoSQL database a deep dive -MyWhitePaper
MongoDB NoSQL database a deep dive -MyWhitePaper
Rajesh Kumar
 
MongoDbPpt based on python installation.
MongoDbPpt based on python installation.
jnvcomputerlab2024
 
Dev Jumpstart: Building Your First App
Dev Jumpstart: Building Your First App
MongoDB
 
Mongodb
Mongodb
Scott Motte
 
FrozenRails Training
FrozenRails Training
Mike Dirolf
 
Dev Jumpstart: Build Your First App with MongoDB
Dev Jumpstart: Build Your First App with MongoDB
MongoDB
 
Webinar: Getting Started with Ruby and MongoDB
Webinar: Getting Started with Ruby and MongoDB
MongoDB
 
MongoDB at FrozenRails
MongoDB at FrozenRails
Mike Dirolf
 
Building your first app with MongoDB
Building your first app with MongoDB
Norberto Leite
 
9. Document Oriented Databases
9. Document Oriented Databases
Fabio Fumarola
 
MongoDB - Ruby document store that doesn't rhyme with ouch
MongoDB - Ruby document store that doesn't rhyme with ouch
Wynn Netherland
 
Introduction to MongoDB
Introduction to MongoDB
Mike Dirolf
 
Introduction to using MongoDB with Ruby
Introduction to using MongoDB with Ruby
Jonathan Holloway
 
Meetup#1: 10 reasons to fall in love with MongoDB
Meetup#1: 10 reasons to fall in love with MongoDB
Minsk MongoDB User Group
 
MongoDB: a gentle, friendly overview
MongoDB: a gentle, friendly overview
Antonio Pintus
 
MongoDB NoSQL database a deep dive -MyWhitePaper
MongoDB NoSQL database a deep dive -MyWhitePaper
Rajesh Kumar
 
MongoDbPpt based on python installation.
MongoDbPpt based on python installation.
jnvcomputerlab2024
 
Dev Jumpstart: Building Your First App
Dev Jumpstart: Building Your First App
MongoDB
 
FrozenRails Training
FrozenRails Training
Mike Dirolf
 
Ad

More from Steven Francia (17)

State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017
Steven Francia
 
Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)
Steven Francia
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and Hadoop
Steven Francia
 
Future of data
Future of data
Steven Francia
 
Replication, Durability, and Disaster Recovery
Replication, Durability, and Disaster Recovery
Steven Francia
 
Multi Data Center Strategies
Multi Data Center Strategies
Steven Francia
 
NoSQL databases and managing big data
NoSQL databases and managing big data
Steven Francia
 
MongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous Data
Steven Francia
 
MongoDB for Genealogy
MongoDB for Genealogy
Steven Francia
 
Hybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS Applications
Steven Francia
 
Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011
Steven Francia
 
MongoDB, E-commerce and Transactions
MongoDB, E-commerce and Transactions
Steven Francia
 
MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011
Steven Francia
 
MongoDB and PHP ZendCon 2011
MongoDB and PHP ZendCon 2011
Steven Francia
 
Blending MongoDB and RDBMS for ecommerce
Blending MongoDB and RDBMS for ecommerce
Steven Francia
 
Augmenting RDBMS with MongoDB for ecommerce
Augmenting RDBMS with MongoDB for ecommerce
Steven Francia
 
MongoDB and Ecommerce : A perfect combination
MongoDB and Ecommerce : A perfect combination
Steven Francia
 
State of the Gopher Nation - Golang - August 2017
State of the Gopher Nation - Golang - August 2017
Steven Francia
 
Modern Database Systems (for Genealogy)
Modern Database Systems (for Genealogy)
Steven Francia
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and Hadoop
Steven Francia
 
Replication, Durability, and Disaster Recovery
Replication, Durability, and Disaster Recovery
Steven Francia
 
Multi Data Center Strategies
Multi Data Center Strategies
Steven Francia
 
NoSQL databases and managing big data
NoSQL databases and managing big data
Steven Francia
 
MongoDB, Hadoop and Humongous Data
MongoDB, Hadoop and Humongous Data
Steven Francia
 
Hybrid MongoDB and RDBMS Applications
Hybrid MongoDB and RDBMS Applications
Steven Francia
 
Building your first application w/mongoDB MongoSV2011
Building your first application w/mongoDB MongoSV2011
Steven Francia
 
MongoDB, E-commerce and Transactions
MongoDB, E-commerce and Transactions
Steven Francia
 
MongoDB, PHP and the cloud - php cloud summit 2011
MongoDB, PHP and the cloud - php cloud summit 2011
Steven Francia
 
MongoDB and PHP ZendCon 2011
MongoDB and PHP ZendCon 2011
Steven Francia
 
Blending MongoDB and RDBMS for ecommerce
Blending MongoDB and RDBMS for ecommerce
Steven Francia
 
Augmenting RDBMS with MongoDB for ecommerce
Augmenting RDBMS with MongoDB for ecommerce
Steven Francia
 
MongoDB and Ecommerce : A perfect combination
MongoDB and Ecommerce : A perfect combination
Steven Francia
 

Recently uploaded (20)

Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
Bridging the divide: A conversation on tariffs today in the book industry - T...
Bridging the divide: A conversation on tariffs today in the book industry - T...
BookNet Canada
 
Reducing Conflicts and Increasing Safety Along the Cycling Networks of East-F...
Reducing Conflicts and Increasing Safety Along the Cycling Networks of East-F...
Safe Software
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 
Down the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training Roadblocks
Rustici Software
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
Murdledescargadarkweb.pdfvolumen1 100 elementary
Murdledescargadarkweb.pdfvolumen1 100 elementary
JorgeSemperteguiMont
 
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
Edge AI and Vision Alliance
 
Oracle Cloud and AI Specialization Program
Oracle Cloud and AI Specialization Program
VICTOR MAESTRE RAMIREZ
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
AudGram Review: Build Visually Appealing, AI-Enhanced Audiograms to Engage Yo...
AudGram Review: Build Visually Appealing, AI-Enhanced Audiograms to Engage Yo...
SOFTTECHHUB
 
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
Edge AI and Vision Alliance
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
FME for Good: Integrating Multiple Data Sources with APIs to Support Local Ch...
FME for Good: Integrating Multiple Data Sources with APIs to Support Local Ch...
Safe Software
 
“Addressing Evolving AI Model Challenges Through Memory and Storage,” a Prese...
“Addressing Evolving AI Model Challenges Through Memory and Storage,” a Prese...
Edge AI and Vision Alliance
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
June Patch Tuesday
June Patch Tuesday
Ivanti
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 
Supporting the NextGen 911 Digital Transformation with FME
Supporting the NextGen 911 Digital Transformation with FME
Safe Software
 
Bridging the divide: A conversation on tariffs today in the book industry - T...
Bridging the divide: A conversation on tariffs today in the book industry - T...
BookNet Canada
 
Reducing Conflicts and Increasing Safety Along the Cycling Networks of East-F...
Reducing Conflicts and Increasing Safety Along the Cycling Networks of East-F...
Safe Software
 
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
vertical-cnc-processing-centers-drillteq-v-200-en.pdf
AmirStern2
 
Down the Rabbit Hole – Solving 5 Training Roadblocks
Down the Rabbit Hole – Solving 5 Training Roadblocks
Rustici Software
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
Murdledescargadarkweb.pdfvolumen1 100 elementary
Murdledescargadarkweb.pdfvolumen1 100 elementary
JorgeSemperteguiMont
 
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
Edge AI and Vision Alliance
 
Oracle Cloud and AI Specialization Program
Oracle Cloud and AI Specialization Program
VICTOR MAESTRE RAMIREZ
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
AudGram Review: Build Visually Appealing, AI-Enhanced Audiograms to Engage Yo...
AudGram Review: Build Visually Appealing, AI-Enhanced Audiograms to Engage Yo...
SOFTTECHHUB
 
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
“Why It’s Critical to Have an Integrated Development Methodology for Edge AI,...
Edge AI and Vision Alliance
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
FME for Good: Integrating Multiple Data Sources with APIs to Support Local Ch...
FME for Good: Integrating Multiple Data Sources with APIs to Support Local Ch...
Safe Software
 
“Addressing Evolving AI Model Challenges Through Memory and Storage,” a Prese...
“Addressing Evolving AI Model Challenges Through Memory and Storage,” a Prese...
Edge AI and Vision Alliance
 
Oracle Cloud Infrastructure Generative AI Professional
Oracle Cloud Infrastructure Generative AI Professional
VICTOR MAESTRE RAMIREZ
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
June Patch Tuesday
June Patch Tuesday
Ivanti
 
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Agentic AI: Beyond the Buzz- LangGraph Studio V2
Shashikant Jagtap
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 

Build your first MongoDB App in Ruby @ StrangeLoop 2013

  • 2. Agda Introduction to MongoDB MongoDB Fundamentals Running MongoDB Schema Design Ruby & Sinatra Crash Course Building Our First App
  • 3. @spf13Steve Francia AKA Chief Developer Advocate @ responsible for drivers, integrations, web & docs
  • 6. * Document * Open source * High performance * Horizontally scalable * Full featured MongoDB is a ___________ database
  • 7. * Not for .PDF & .DOC files * A document is essentially an associative array * Document == JSON object * Document == PHP Array * Document == Python Dict * Document == Ruby Hash * etc Documt Database
  • 8. * MongoDB is an open source project * On GitHub * Licensed under the AGPL * Commercial licenses available * Contributions welcome Op Source
  • 9. * Written in C++ * Extensive use of memory-mapped files i.e. read-through write-through memory caching. * Runs nearly everywhere * Data serialized as BSON (fast parsing) * Full support for primary & secondary indexes * Document model = less work High Pfoance
  • 11. * Ad Hoc queries * Real time aggregation * Rich query capabilities * Traditionally consistent * Geospatial features * Support for most programming languages * Flexible schema Full Ftured
  • 14. What is a Record?
  • 15. K → Value * One-dimensional storage * Single value is a blob * Query on key only * No schema * Value cannot be updated, only replaced Key Blob
  • 16. Raonal * Two-dimensional storage (tuples) * Each field contains a single value * Query on any field * Very structured schema (table) * In-place updates * Normalization process requires many tables, joins, indexes, and poor data locality Primary Key
  • 17. Documt * N-dimensional storage * Each field can contain 0, 1, many, or embedded values * Query on any field & level * Flexible schema * Inline updates * * Embedding related data has optimal data locality, requires fewer indexes, has better performance _id
  • 21. user = { username: 'fred.jones', first_name: 'fred', last_name: 'jones', } Sta wh an object (or ay, hash, dict, c)
  • 22. > db.users.insert(user) Inst e record No collection creation needed
  • 23. > db.users.findOne() { "_id" : ObjectId("50804d0bd94ccab2da652599"), "username" : "fred.jones", "first_name" : "fred", "last_name" : "jones" } Quying for e us
  • 24. * _id is the primary key in MongoDB * Automatically indexed * Automatically created as an ObjectId if not provided * Any unique immutable value could be used _id
  • 25. * ObjectId is a special 12 byte value * Guaranteed to be unique across your cluster * ObjectId("50804d0bd94ccab2da652599") |-------------||---------||-----||----------| ts mac pid inc ObjectId
  • 29. 4 Building blocks of Documt Design
  • 30. exibi * Choices for schema design * Each record can have different fields * Field names consistent for programming * Common structure can be enforced by application * Easy to evolve as needed
  • 31. Ays * Each field can be: * Absent * Set to null * Set to a single value * Set to an array of many values * Query for any matching value * Can be indexed and each value in the array is in the index
  • 32. beed Documts * An acceptable value is a document * Nested documents provide structure * Query any field at any level * Can be indexed
  • 33. * Object in your model * Associations with other entities  Aßociaon Referencing (Relational) Embedding (Document) has_one embeds_one belongs_to embedded_in has_many embeds_many has_and_belongs_to_many MongoDB has both referencing and embedding for universal coverage
  • 34. Excise 1: Mod a busineß card
  • 36. Contacts { “_id”: 2, “name”: “Steven Jobs”, “title”: “VP, New Product Development”, “company”: “Apple Computer”, “phone”: “408-996-1010”, “address_id”: 1 } Rcing Addresses { “_id”: 1, “street”: “10260 Bandley Dr”, “city”: “Cupertino”, “state”: “CA”, “zip_code”: ”95014”, “country”: “USA” }
  • 37. Contacts { “_id”: 2, “name”: “Steven Jobs”, “title”: “VP, New Product Development”, “company”: “Apple Computer”, “address”: { “street”: “10260 Bandley Dr”, “city”: “Cupertino”, “state”: “CA”, “zip_code”: ”95014”, “country”: “USA” }, “phone”: “408-996-1010” } being
  • 38. Excise 2: Store a busineß card
  • 39. Contacts db.contacts.insert( { “_id”: 2, “name”: “Steven Jobs”, “title”: “VP, New Product Development”, “company”: “Apple Computer”, “phone”: “408-996-1010”, “address_id”: 1 } ) Insng wh Rce Addresses db.addresses.insert( { “_id”: 1, “street”: “10260 Bandley Dr”, “city”: “Cupertino”, “state”: “CA”, “zip_code”: ”95014”, “country”: “USA” } )
  • 40. Excise 3: Re a busineß card
  • 41. Contacts c = db.contacts.findOne( { “name”: “Steven Jobs”, } ) Quying wh Rce Addresses db.addresses.findOne( { “_id”: c.address_id, “street”: “10260 Bandley Dr”, “city”: “Cupertino”, “state”: “CA”, “zip_code”: ”95014”, “country”: “USA” } )
  • 43. MongoDB has nave bindings for nr allnguages
  • 44. Official Support for 12 languages Community drivers for tons more Drivers connect to mongo servers Drivers translate BSON into native types mongo shell is not a driver, but works like one in some ways Installed using typical means (npm, pecl, gem, pip) MongoDB dvs
  • 47. Building an a in Ruby? Had to pick a language Sinatra is very minimal and approachable Wanted to focus on MongoDB interaction Ruby gems are awesome Works well on Windows, OS X & Linux Seemed like a good idea at the time
  • 49. hing is an object 1.class 'a'.class :z.class class Foo end Foo.class Foo.new.class # => Fixnum # => String # => Symbol # => Class # => Foo
  • 50. Structure Method Class Invocation def do_stuff(thing) thing.do_the_stuff end class TheThing def do_the_stuff puts "Stuff was done!" end end do_stuff(TheThing.new)
  • 51. Stngs name = 'World' # => "World" "Hello, #{name}" # => "Hello, World" 'Hello, #{name}' # => "Hello, #{name}"
  • 52. Numbs 1 + 1 # => 2 1 + 1.1 # => 2.1 6 * 7 # => 42 6 ** 7 # => 279936 Math.sqrt(65536) # => 256.0 1.class # => Fixnum (2 ** 42).class # => Fixnum (2 ** 64).class # => Bignum 1.1.class # => Float
  • 53. Ays Array.new Array.new(3) [] a = [1,2,3] a[0] = 'one' a a[-1] a[1..2] # => [] # => [nil, nil, nil] # => [] # => [1, 2, 3] # => "one" # => ["one", 2, 3] # => 3 # => [2, 3]
  • 54. Hashes Hash.new {} h = {1 => "one", 2 => "two"} h[1] h["1"] h[:one] = "einz" h[:one] h.keys h.values # => {} # => {} # => "one" # => nil # => "einz" # => "einz" # => [1, 2, :one] # => ["one", "two", "einz"]
  • 55. Vaables & Names CamelCased # Classes, modules with_underscores # methods, local variables @instance_variable @@class_variable $GLOBAL_VARIABLE
  • 56. Corol Structuresif condition # ... elsif other_condition # ... end unless condition # ... end while # ... end
  • 58. Sinat is... not Rails not a framework a DSL for quickly creating web applications in Ruby with minimal effort
  • 59. Hlo World # myapp.rb require 'sinatra' get '/' do 'Hello world!' end
  • 60. TP Acons 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 .. end post '/' do .. create something .. end put '/' do .. replace something .. end delete '/' do .. annihilate something .. end
  • 61. Roes 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
  • 62. Spt 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"] end get '/download/*.*' do # matches /download/path/to/file.xml params[:splat] # => ["path/to/file", "xml"] end
  • 66. Download & Impo e vues curl -L http://j.mp/StrangeLoopVenues | mongoimport -d milieu -c venues wget http://c.spf13.com/dl/StrangeLoopVenues.json mongoimport -d milieu -c venues StrangeLoopVenues.json Database Collection
  • 68. L’s lk at e vues > use milieu switched to db milieu > db.venues.count() 50 Database
  • 69. L’s lk at e vues > db.venues.findOne() { "_id" : ObjectId("52335163695c9d31c2000001"), "location" : { "address" : "1820 Market St", "distance" : 85, "postalCode" : "63103", "city" : "Saint Louis", "state" : "MO", "country" : "United States", "cc" : "US", "geo" : [ -90.20761747801353, 38.62893438211461 ] }, "name" : "St. Louis Union Station Hotel- A DoubleTree by Hilton", "contact" : { "phone" : "3146215262", "formattedPhone" : "(314) 621-5262", "url" : "http://www.stlunionstationhotel.com" }, "stats" : { "checkinsCount" : 0, "usersCount" : 0 } }
  • 70. Crng 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_" } ]
  • 72. Sta wh a skon /Users/steve/Code/milieu/app/ ▸ config/ ▸ helpers/ ▾ model/ mongodb.rb mongoModule.rb user.rb ▾ public/ ▸ bootstrap/ ▾ css/ styles.css ▸ images/ ▾ views/ footer.haml index.haml layout.haml login.haml navbar.haml register.haml user_dashboard.haml user_profile.haml venue.haml venues.haml app.rb config.ru Gemfile Rakefile README
  • 73. Download & Install deps mkdir milieu cd milieu wget http://c.spf13.com/dl/GettingStarted.tgz tar zxvf GettingStarted.tgz bundle install Resolving dependencies... Using bson (1.9.2) Using bson_ext (1.9.2) Using googlestaticmap (1.1.4) Using tilt (1.4.1) Using haml (4.0.3) Using mongo (1.9.2) Using rack (1.5.2) Using rack-protection (1.5.0) Using shotgun (0.9) Using sinatra (1.4.3) Using bundler (1.3.5) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
  • 74. Run a shotgun == Shotgun/WEBrick on http://127.0.0.1:9393/ [2013-09-13 21:25:43] INFO WEBrick 1.3.1 [2013-09-13 21:25:43] INFO ruby 2.0.0 (2013-06-27) [x86_64-darwin12.3.0] [2013-09-13 21:25:43] INFO WEBrick::HTTPServer#start: pid=85344 port=9393
  • 75. Op Brows to locaost:9393
  • 78. Connecng to MongoDB require 'mongo' require './model/mongoModule' require './model/user' # Connection code goes here CONNECTION = Mongo::Connection.new("localhost") DB = CONNECTION.db('milieu') # Alias to collections goes here USERS = DB['users'] VENUES = DB['venues'] CHECKINS = DB['checkins'] model/mongodb.rb
  • 79. sng Vues get '/venues' do # Code to list all venues goes here @venues = VENUES.░░░░░ haml :venues end app.rb
  • 80. sng Vues get '/venues' do # Code to list all venues goes here @venues = VENUES.find haml :venues end app.rb
  • 81. sng Vues .container .content %h2 Venues %table.table.table-striped %thead %tr %th Name %th Address %th Longitude %th Latitude %tbody [email protected] 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) views/venues.haml
  • 83. Paginang Vues get '/venues/?:page?' do @page = params.fetch('page', 1).to_i pp = 10 @venues = VENUES.find.░░░░░(░░░░).░░░░(░░░) @total_pages = (VENUES.░░░░░.to_i / pp).ceil haml :venues end app.rb # replaces the prior entry
  • 84. Paginang Vues get '/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 :venues end app.rb # replaces the prior entry
  • 85. .container .content %h2 Venues %table.table.table-striped %thead %tr %th Name %th Address %th Longitude %th Latitude %tbody [email protected] 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) =pager('/venues') sng Vues views/venues.haml
  • 88. Crng Uss Users are a bit special in our app Not just data Special considerations for secure password handling Not complicated on MongoDB side, but slightly complicated on Ruby side
  • 89. Crng Uss class User attr_accessor :_id, :name, :email, :email_hash, :salt, :hashed_password, :collection, :updated_at def init_collection 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) end end model/user.rb Inherited from MongoModule.rb
  • 90. Crng Uss post '/register' do 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' end end app.rb
  • 91. Loing in pa 1 configure do enable :sessions end before do unless session[:user] == nil @suser = session[:user] end end get '/user/:email/dashboard' do haml :user_dashboard end app.rb
  • 92. Loing in pa 2 post '/login' do if session[:user] = User.auth(params["email"], params["password"]) flash("Login successful") redirect "/user/" << session[:user].email << "/dashboard" else flash("Login failed - Try again") redirect '/login' end end app.rb
  • 93. Loing in pa 3 def self.auth(email, pass) u = USERS.find_one("email" => email.downcase) return nil if u.nil? return User.new(u) if User.encrypt( pass, u['salt']) == u['hashed_password'] nil end user.rb
  • 94. Us Dashboard .container .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 views/user_dashboard.haml
  • 97. nding a us get '/user/:email/profile' do u = USERS.░░░░░( ░░░░░ => ░░░░░.░░░░░) if u == nil return haml :profile_missing else @user = User.new(u) end haml :user_profile end app.rb
  • 98. nding a us get '/user/:email/profile' do u = USERS.find_one( "email" => params[:email].downcase) if u == nil return haml :profile_missing else @user = User.new(u) end haml :user_profile end app.rb
  • 99. Crng an INdex > db.users.ensureIndex({email : 1}) > db.users.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "milieu.users", "name" : "_id_" }, { "v" : 1, "key" : { "email" : 1 }, "ns" : "milieu.users", "name" : "email_1" } ]
  • 101. Showing a Vue get '/venue/:_id' do object_id = ░░░░░░░░░░░░░░ @venue = ░░░░░░░░░░( { ░░░░ => object_id }) haml :venue end app.rb
  • 102. Showing a Vue get '/venue/:_id' do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one( { :_id => object_id }) haml :venue end app.rb
  • 103. Showing a Vue .row .col-md-4 %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 .col-md-8 %image{:src => '' << gmap_url(@venue, {:height => 300, :width => 450}) } views/venue.haml
  • 106. Nrby Vues get '/venue/:_id' do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) @nearby_venues = ░░░░░.░░░░░( {░░░░░ =>{░░░░░=>[ ░░░░░,░░░░░]}} ).░░░░░(4).░░░░░(1) haml :venue end app.rb
  • 107. Nrby Vues get '/venue/:_id' do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) @nearby_venues = VENUES.find( { :'location.geo' => { ░░░░░ => [ ░░░░░,░░░░░] } }).░░░░░(4).░░░░░(1) haml :venue end app.rb
  • 108. Nrby Vues get '/venue/:_id' do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) @nearby_venues = VENUES.find( { :'location.geo' => { ░░░░░ => [ ░░░░░,░░░░░] } }).limit(4).skip(1) haml :venue end app.rb
  • 109. Nrby Vues get '/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 :venue end app.rb
  • 110. ... .row - @nearby_venues.each do |nearby| .col-md-3 %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}) } views/venue.haml sng Nrby Vues
  • 113. Checng in get '/venue/:_id/checkin' do object_id = BSON::ObjectId.from_string(params[:_id]) @venue = VENUES.find_one({ :_id => object_id }) user = USERS. ░░░░░_and_░░░░░(░░░░░) if ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ else ░░░░░ ░░░░░ ░░░░░ ░░░░░ end flash('Thanks for checking in') redirect '/venue/' + params[:_id] end app.rb
  • 114. Checng in get '/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 => ░░░░░, :update => ░░░░░, :new => 1) if ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ else ░░░░░ ░░░░░ ░░░░░ ░░░░░ end flash('Thanks for checking in') redirect '/venue/' + params[:_id] end app.rb
  • 115. Checng in get '/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 ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ else ░░░░░ ░░░░░ ░░░░░ ░░░░░ end flash('Thanks for checking in') redirect '/venue/' + params[:_id] end app.rb
  • 116. Checng in get '/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(░░░░░) else VENUES.update(░░░░░) end flash('Thanks for checking in') redirect '/venue/' + params[:_id] end app.rb
  • 117. Checng in get '/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 app.rb
  • 118. You’ve be he def user_times_at if logged_in? times = 'You have checked in here ' if [email protected]? && [email protected][params[:_id]].nil? times << @suser.venues[params[:_id]].to_s else times << '0' end times << ' times' else times = 'Please <a href='/login'>login</a> to join them.' end end helpers/milieu.rb
  • 119. Checn In %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 views/venue.haml
  • 121. What we’ve led * Model data for MongoDB * Use MongoDB tools to import data * Create records from shell & ruby * Update records * Atomic updates * Create an index * Create a geo index * Query for data by matching * GeoQueries * Pagination * Single Document Transactions * Some ruby, sinatra, haml, etc
  • 122. Next ?
  • 124. Some Ids* Create interface to add venues * Connect to foursquare * Login w/twitter * Badges or Categories * Enable searching of venues * Tips / Reviews
  • 125. E IF YOU KED ! Questions? http://spf13.com http://github.com/spf13 @spf13