You are on page 1of 61

NoSQL: MongoDB y MongoMapper

Patrick Aljord, David y Jorge Cuadrado


Tokyo Cabinet

BigTable
Características

Esquema libre
Distribuidas y escalables
Capacidad de manejo de
grandes volúmenes de datos
Performance/rendimiento
Tipos de NoSQL

Key/Value (Llave/valor)
Column-oriented (orientadas a columnas)
Document-oriented (orientadas a
documentos)
Key/Value
¿Qué es?
una llave
un blob

Ventajas:
muy simple para implementar
muy rapido

Útil para:
el cache(memcache)
sistema de manejo de cola (redis)

limitado para aplicaciones complejas


Column-oriented
¿Qué es?
utiliza tablas dinamicas
mas flexible que tablas de RDBMS
multi-dimensional

Ventajas:
el sistema de consulta se acerca al de un RDBMS
diseño de google, soporta grandes cargas
versiones

Útil para:
grandes colecciones

mapping de los datos a objetos no es natural (igual que


rdbms)
Document-oriented
¿Qué es?
formato json o xml
muy flexible

Ventajas:
mapea facilmente a un objeto (python, ruby, c++ etc)

Útil para:
aplicaciones web complejas
todo tipo de aplicacion que utiliza documentos y
necesita flexibilidad
La soluciones que aporta el NoSQL

built-in replication, master a master


Map/Reduce
mas simple de instalar (se necesita tomar un curso
para instalar a oracle o sqlserver)
casi todas son software libre, muy accesible para
todos
hecho para programadores, mas orientadas a la
programaciones (map/reduce lo entienden mejor los
programadores que los administradores de base de
datos)
¿Qué es el map/reduce?

Permite procesar los datos guardados en un cluster de


computadores de forma paralela.
Sus resultados son similares a los de una función de
agregación como GROUP BY en SQL.
¿Que es el map?

El map es aplicar una función sobre cada elemento de un


arreglo y retornar un arreglo con sus elementos
modificados.

Ejemplo (en ruby):


> matriz = [1,2]
> matriz.map { |n| n+2 }
=> [3, 4]
¿Qué es el reduce?

Reduce es aplicar una función sobre cada elemento de un


arreglo y retornar un solo elemento. Se hace iterando sobre
cada elemento del arreglo. Cada iteracion empieza con el
valor retornado por la iteracion anterior y hace algo con
esta. Por esta razón, un reduce se debe iniciar con una
valor de entrada.

ejemplo (en ruby), con valor de entrada igual a cero:


> [1, 2, 3].reduce(0) do |sum, value|
sum + value
end
=> 6
Las ventajas del map/reduce

Esta hecho para poderse ejecutar en paralelo


=> Fácil de dividir en varias tareas
Todos los datos se pueden agrupar.
Probado y comprobado por los grande(google, amazon,
facebook).
(credit: amazon)
SQL-RDBMS Key/Value

Variedad de
consultas Rendimiento
Las principales funcionalidades

Document-oriented storage
Consultas
Modificadores atómicos
Map/Reduce
GridFS: Almacenamiento de archivos
Soporte para Full Index
Replicación & Alta Disponibilidad
Auto-Sharding
¿Como instalar MongoDB?

1. Para instalar mongodb descargamos el binario


correspondiente para nuestro sistema operativo http://www.
mongodb.org/display/DOCS/Downloads
2. descomprimes el paquete y creas los directorios /data y
/data/db o C:\data y C:\data dependiendo de tu SO
3. para iniciar el servicio corres el binario /bin/mongod o
bin\mongod.exe que viene en el paquete que has
descargado en el paso 1

para un entorno de producción se debe usar un sistema


operativo de 64-bits.
¿Como instalar mongodb?

Para los sistemas unix*(linux,freebsd, OSX) es recomendado


usar el sistema de paquetes de cada sistema operativo.

adicionalmente 10gen provee de paquetes oficiales para las


distribuciones Linux Debian, Ubuntu, CentOS y Fedora

http://www.mongodb.
org/display/DOCS/Ubuntu+and+Debian+packages
http://www.mongodb.
org/display/DOCS/CentOS+and+Fedora+Packages
¿ Cómo se guardan los datos
en MongoDB?

Colección:
Documento:
la música que tiene
Álbum de un
el almacén
artista
¿BSON?
{
nombre: "Yellow Submarine",
autor: "The Beatles",
canciones: ["Yellow Submarine", "Only A Northern Song",
"All Together Now", "Hey Bulldog",
"It's All Too Much", "All You Need Is Love",
"Pepperland", "Sea Of Time",
"Sea Of Holes", "Sea Of Monsters",
"March Of The Meanies", "Pepperland Laid Waste",
"Yellow Submarine In Pepperland" ],
genero: "Rock",
anho: 1969,
cantidad: 20
}
¿Que tipos de datos se pueden
guardar en MongoDB?
ObjectID (identificador del documento)
Números(Reales y Enteros)
Arreglos
Objetos(Hash)
Binarios(Blobs)
Tiempos(UTC)
vacio(nil, null)

http://bsonspec.org/
¿Cómo conectarse a mongoDB?
console: ./bin/mongo

Drivers Oficiales: Drivers Comunitarios:


C C# and .NET
C++ Clojure
Java Erlang
Javascript Go
Perl Groovy
PHP Haskell
Python node.js
Ruby Lua
LuaMongo
Scala
Scheme (PLT)
Smalltalk
http://www.mongodb.org/display/DOCS/Drivers
Referenciar o Empotrar
Album
{
_id: "aaa",
nombre: "Yellow Submarine",
autor: "The Beatles",
genero: "Rock",
anho: 1969,
cantidad: 20
}

Cancion
{ nombre: "Yellow Submarine", duracion: 159, album_id: "aaa" },
{ nombre: "Only A Northern Song", duracion: 204, album_id: "aaa" }
{ nombre: "All Together Now", duracion: 130, album_id: "aaa" }
{ nombre: "Hey Bulldog", duracion: 191, album_id: "aaa" }
{ nombre: "It's All Too Much", duracion: 384, album_id: "aaa"}
{ nombre: "All You Need Is Love", duracion: 231, album_id: "aaa"}
Referenciar o Empotrar
{
nombre: "Yellow Submarine",
autor: "The Beatles",
canciones: [ { nombre: "Yellow Submarine", duracion: 159 },
{ nombre: "Only A Northern Song", duracion: 204 },
{ nombre: "All Together Now", duracion: 130 },
{ nombre: "Hey Bulldog", duracion: 191 },
{ nombre: "It's All Too Much", duracion: 384 },
{ nombre: "All You Need Is Love", duracion: 231 },
...],
genero: "Rock",
anho: 1969,
cantidad: 20
}
¿Cómo añadir y eliminar documentos a
una colección?
./mongo
> use tienda_de_musica
> album = {
nombre: "Let it be", autor: "The Beatles", canciones: [],
genero: "Rock", anho: 1970, cantidad: 10 }
> db.musica.save(album);
> db.musica.find();
{ "_id" : ObjectId("4c10a976eaa67158a0d74b4b"), "nombre":
"Let it be", "autor" : "The Beatles", "canciones" : [ ], "genero" :
"Rock", "anho" : 1970, "cantidad" : 10 }

>db.musica.remove({});
>db.musica.remove({autor: "The Beatles"})
¿Como actualizar un documento?
Modificadores
db.coleccion.update( criterio_de_busqueda,
objeto_o_operadores,
[upsert?], [múltiple?])

>db.musica.update( {_id: ObjectId


("4c10a976eaa67158a0d74b4b")}, {$inc: { cantidad: -1 }});

>db.musica.update( _id: 10, $set: { cantidad: 0 }, true);

http://www.mongodb.org/display/DOCS/Updating
Un poco más acerca de los
modifcadores
$set y $unset: sirven para asignarle y quitarle el valor a un
campo de un documento respectivamente.
$inc: incrementan el valor asignado a un campo, solo es valido
para valores enteros.
$push,$pushAll: añaden uno o varios valores a un arreglo de
datos contenido en un campo del documento.
$addToSet: añade un valor a un arreglo si el valor no esta
repetido.
$pop, $pull, $pullAll: son operadores para borrar los valores
contenidos en un arreglo.

http://www.mongodb.org/display/DOCS/Updating
¿Cómo hacer consultas en MongoDB?
Operadores condicionales para describir criterios de búsqueda:
$gt(>) $lt(<), $gte(<=), $lte(>=), $ne(!=)
>db.things.find({j : {$lt: 3}});
$exists chequea que el documento tenga o no un campo
> db.things.find( { a : { $exists : true } } );

Operadores solo para arreglos:


>db.things.find(a : {$in: x}
$in a incluye al menos un valor del arreglo x.
$nin negación de $in
>db.things.find(a : {$all: x}
$all a incluye todos los valores de x

http://www.mongodb.org/display/DOCS/Advanced+Queries
¿Cómo hacer consultas en MongoDB?
WHERE
sql> select * from musica where cantidad=1;
> db.musica.find({cantidad: 1});
sql> select nombre from musica where cantidad<2;
> db.musica.find({cantidad: {$lt: 2}}, {'nombre': 1});
sql>select * from musica where name like 'The%';
>db.musica.find( { name : /^The/ } );

ORDER BY
sql> select * from musica ORDER BY anho desc;
> db.musica.find({}).sort({anho: -1});

LIMIT y OFFSET
sql> select * from musica LIMIT 10 OFFSET 5;
>db.musica.find().skip(5).limit(10)
¿Cómo hacer consultas en MongoDB?
COUNT
sql>SELECT COUNT(*) FROM musica WHERE autor = "The
Beatles";
>db.musica.count({autor: "The Beatles"})

DISTINCT
sql> select distinct autor from musica;
>db.musica.distinct("autor")
¿Cómo hacer consultas en MongoDB?
GROUP BY
sql>select autor, count(*) from musica where genero="rock"
group by autor

db.musica.group({key: { autor: true },


cond: { genero: "Rock" },
reduce: function(obj, prev) {
prev.csum += obj.cantidad;
},
initial: { csum: 0 }});
¿Como usar map/reduce
en MongoDB?

// MapReduce esta hecho para hacer operaciones de agregaciones.


// Tomamos documentos de la coleccion Comentario:

{ text: "jajaja! buena presentacion!", author: 'eliot', votes: 2 }


// Aqui tenemos un documento Comentario con un autor, el
texto y la cantidad de votos.
¿Como usar map/reduce
en MongoDB?
// Queremos calcular la cantidad de votos para cada autor de
todos los comentarios que han hecho.
var map = function() { emit(this.author, {votes: this.votes}); };

// Esto devuelve una colleccion de pares de llave valor como:


[ {"eliot", {votes: 2}}, {"eliot", {votes: 5}}, {"dwight", {votes: 3}} ]
¿Como usar map/reduce
en MongoDB?
// A la funcion reduce, se manda cada llave unica y una
matriz conteniendo todos los valores para esta llave, // por
ejemplo para la llave "eliot", reduce recibe:
reduce("eliot", [{votes: 2}, {votes: 5}]);

// Teniendo eso, es fácil para cada autor obtener la suma


de todos los votos que han obtenido en todos sus
comentarios:
var reduce = function(key, values) {
var sum = 0;
values.forEach(function(doc) { sum += doc.votes; });
return {votes: sum};
};
¿Como usar map/reduce
en MongoDB?
// Se ejecuta así:
var op = db.comments.mapReduce(map, reduce);

// Para obtener los resultados:


db[op.result].find(); [{ "_id" : "eliot", "value" : { "votes" : 7 }
}, { "_id" : "kbanker", "value" : { "votes" : 3 } }]
¿GridFS?

Almacenamiento de archivos de todo tamaño sin


comprometer su stack.

Viene con binarios y bibliotecas

API simple: list, put, get, delete


Sharding

Auto-Sharding
particionamento de los datos en varios servidor
sharding por coleccion
proceso mongos (routing)
replica set
Sharding

http://www.mongodb.org/display/DOCS/Sharding+Introduction
Información Geo espacial
¿Quienes usan MongoDB?

http://www.mongodb.
org/display/DOCS/Production+Deployments
http://mongomapper.com/
http://github.com/jnunemaker/mongomapper
¿Como empezar a usar
MongoMapper?
Instalar
>sudo gem install mongo_mapper

Incluir en el proyecto Rails


agregar la la dependencia en config/environment.rb
config.gem "mongo_mapper", :version => "0.8.2", :source =>
"http://gemcutter.org"
¿Como empezar a usar
MongoMapper?
Configurar la conexión a la base de datos
config/database.yml

development:
database: nombre-del-proyecto-development
host: localhost
port: 27017
test:
database: nombre-del-proyecto-test
production:
database: nombre-del-proyecto-production
Incluir en el proyecto Rails
Configurar la conexión a la base de datos
config/initializers/mongodb.rb
MongoMapper.setup(YAML.load_file(Rails.root.join('config',
'database.yml')), Rails.env, { :logger => Rails.logger, :passenger =>
false })
¿Cómo definir un modelo?

app/model/album.rb

class Album
include MongoMapper::Document
key :nombre, String
key :autor, String
key :genero, String
key :anho, Integer
key :cantidad, Integer
key :canciones, Array
end
¿Comó definir un modelo empotrado?

app/model/cancion.rb
class Cancion
include MongoMapper::EmbeddedDocument
key :name, String
key :duracion, Integer
end
app/model/album.rb
class Album
include MongoMapper::Document
...
has_many :canciones, :class_name => "Cancion"
end
¿Que tipo de llaves existen?

los tipos de llaves que estan definidos en MongoMapper son:

ObjectID
String
Integer
Boolean
Array
Hash
Time
Binary
Set
¿Se pueden definir nuevo tipos de
llaves?
class Point
attr_reader :x, :y

def self.to_mongo(value)...end
def self.from_mongo(value)...end

def initialize(*args)...end
end
¿Cómo se definen las relaciones uno a
muchos?
class Album
...
has_many :canciones
...
end

class Cancion
...
key :album_id, ObjectID
belongs_to :album
...
end
¿Cómo se definen las relaciones uno a
uno?
class Cancion
...
has_one :video
...
end

class Video
...
key :cancion_id, ObjectID
belongs_to :cancion
...
end
¿Cómo se definen las relaciones
muchos a muchos?
class Cancion
...
key :album_ids, Array
many :albums, :in => :album_ids
...
end

class Album
...
key :canciones_ids, Array
has_many :canciones, :in => :canciones_ids
...
end
¿MongoMapper tiene
relaciones polimorfas?
class Comment
...
key :commentable_id, ObjectId
key :commentable_type, String
belongs_to :commentable, :polymorphic => true
end

class Album
...
has_many :comments, :as => :commentable, :class_name =>
"Comment"
end
¿Cómo añadir validaciones a los
modelos?
class Album
include MongoMapper::Document
key :nombre, String, :unique => true
key :autor, String, :required => true
key :genero, String, :in => ["Rock", "Pop", "Tropical"]
key :anho, Integer
key :cantidad, Integer
validates_presence_of :nombre, :message => "no ah sido
asignado"
many :canciones
end
¿Qué validaciones existen en
MongoMapper?
required => boolean # necesaria
unique => boolean # unica
format => regexp # con un formato
in => array # incluida
not_in => array # excluida
length => Integer/Range/Hash # tamaño

además puedes usar la api de validatable para agregar mas


validaciónes
validates_presence_of, validates_format_of, validates_true_for,
etc
http://validatable.rubyforge.org/
¿Cómo hacer consultas usando
MongoMapper?
Modelo.find(id_o_ids)
> Album.find("4c10a976eaa67158a0d74b4b")> Album.find
(["4c10a976eaa67158a0d74b4b",
"4c10a976eaa67158a0d74b4c"])
Modelo.first(criterio_opciones)
> Album.first({:genero => "Rock"})

Modelo.all(criterio_opciones)
>Album.all({:cantidad.lt => 5, :limit => 10, :order => "cantidad
asc"})

>Modelo.paginate(criterio_opciones)
Album.paginate(:per_page => 10, :page => 2, :genero
=> "Rock")
¿Cómo usar los modificadores con
MongoMapper?
Modelo.<modifcador>(<criterio>, <valores>)
modificador: increment, decrement, set, unset, push, push_all,
add_to_set, pull, pull_all, pop

>Album.decrement( { :id => "4c10a976eaa67158a0d74b4b"}, {


cantidad: 1 });
>Album.add_to_set( {id: => "4c10a976eaa67158a0d74b4b"},
canciones: "Foo"});

>Album.collection.update(criteria, modificadores, opciones)


>Album.collection.update({:genero => "Rock"}, { "$inc" => {:
cantidad => 10}, "$pop" => {"canciones" : 1} }
¿Preguntas?

http://nosql.shapado.com