Júlio Monteiro
julio@monteiro.eti.br
/ME




Rails Developer, JobScore (http://www.jobscore.com)
/ME




http://julio.monteiro.eti.br
AGENDA
1. Objetivo

2. Histórico

3. Características

4. Relacional versus MongoDB

5. Consultas

6. Map/reduce

7. Operações atômicas

8. Índices

9. Geoposicionamento

10.Por onde continuar?
OBJETIVO


             MongoDB busca aproveitar vantagens
         de armazenamentos de chave-valor
            (que, no geral, são rápidos e escaláveis)
      e banco de dados relacionais tradicionais
(que, no geral, oferecem consultas ricas e várias funcionalidades).

                                   (Adaptado do site oficial do MongoDB)
Quando Chuck Norris fala, todos ficam em silêncio. E morrem.
HISTÓRICO

• Produto    da 10gen

• Desenvolvimento       iniciou em Outubro de 2007

• Primeira   versão pública em Fevereiro de 2009

• Atualmente    na versão 1.6

• Licenciado   sob a GNU AGPL
CARACTERÍSTICAS (1/2)

• Armazenamento      orientado a documentos

• Índices

• Consultas   ricas (rich queries)

• Atualizações   in-place rápidas

• Map/Reduce
CARACTERÍSTICAS (2/2)


• Replicação   e Alta Disponibilidade

• Auto-Sharding

• GridFS

• Suporte   Comercial (da 10gen)
RELACIONAL VERSUS
    MONGODB
TABELA
id    nome    sobrenome   idade

1     Ana        Silva     20

2     Maria    Carvalho    22

3     João      Chaves     21

4     Mário    Schimitd    30

...    ...        ...       ...
DOCUMENTO
Id: 1               Id: 2
Nome: Ana           Nome: Maria
Sobrenome: Silva    Sobrenome: Carvalho
Idade: 20           Idade: 22

Id: 3               Id: 4
Nome: João          Nome: Mário
Sobrenome: Chaves   Sobrenome: Schimitd
Idade: 21           Idade: 30
TERMINOLOGIA
Relacional Tradicional        MongoDB
   (MySQL, PostgreSQL, etc)


        Database              Database
        (Banco de dados)      (Banco de dados)


            Table             Collection
             (Tabela)            (Coleção)


            Row               Document
         (Linha, registro)     (Documento)


         Column               Attribute
            (Coluna)             (Atributo)
MODELO ENTIDADE-
 RELACIONAMENTO
      MYSQL

       artigos           comentarios


artigos_palavras_chave


   palavras_chave
MODELO ENTIDADE
  MONGODB


            comentarios
  artigos
            palavras_chave
DOCUMENTO EM
{               MONGODB
  "_id" : ObjectID("4c03e856e258c2701930c091"),
  "titulo" : "Campus Party Brasil 2011 vêm aí",
  "atalho" : "campus-party-brasil-2011-vem-ai",
  "texto" : "A Campus Party Brasil 2011 está chegando, e com elas diversas
atrações!",
  "publicado" : true,
  "criado_em" : "Mon Oct 4 2010 16:00:00 GMT-0300 (BRT)",
  "atualizado_em" : "Mon Oct 4 2010 16:00:00 GMT-0300 (BRT)",
  "comentarios" : [
     {
       "autor" : "Julio",
       "email" : "julio@monteiro.eti.br",
       "conteudo" : "Gostei muito da Campus!",
       "criado_em" : "Mon Oct 4 2010 17:00:00 GMT-0300 (BRT)"
     }
  ],
  "palavras_chave" : [ "cpbr4", "campus", "party" ]
}
JSON
JavaScript Object Notation
BJSON
Bin  ary
JavaScript Object Notation
CONSULTAS
COMO BUSCO...
• ... por uma palavra inteira?
  db.artigos.find({"titulo" : "campus"})

• ... por parte de uma palavra?
  db.artigos.find({"titulo" : /campus/i})

• ... por uma palavra dentro de um array?
  db.artigos.find({"palavras_chave" : "campus"})

• ... por uma palavra dentro de um embutido?
  db.artigos.find({ "comentarios.email" :
  "julio@monteiro.eti.br" })
COMO ATUALIZO...

... determinado atributo de um registro?
db.artigos.update(
  { "comentarios.email" : "julio@monteiro.eti.br" },
  { $set:
    {
      "comentarios.$.email" : "julio@awegen.com"
    }
  }
)
$SET ?
OPERADORES
$gt
          $all
$gte
          $size
$lt
          $exists
$lte
          $type
$ne
          $elemMatch
$in
          $not
$nin
          $where
$mod
USANDO OPERADORES
• Maior que ($gt):
  terceiraIdade = db.pessoas.find({ "age": { $gt:
  75 } })

• Incluindo ($in):
  interessante = db.artigos.find({ "tags" : { $in :
  ["mongodb", "interessante"] } })

• Não incluindo ($nin):
  todo = db.tarefas.find({ "status" : { $nin : [ "em
  execucao", "terminado" ] } })
FUNÇÕES ARBITRÁRIAS
• Usando funções arbitrárias (com $where):
  db.artigos.find({ $where : function() {
    return this.acessos % 2 == 0
  } })

• Usando agrupamento (com $group):
  db.artigos.group({
     "key" : { "hits" : true },
     "initial" : { "count": 0 },
     "reduce" : function(obj, prev) {
       prev.count++;
     }
  })
FUNÇÃO DE AGRUPAMENTO


• Dado que possui documentos como...
  {
    domain: "www.mongodb.org",
    invoked_at: {d:"2009-11-03", t:"17:14:05"},
    response_time: 0.05,
    http_action: "GET /display/DOCS/Aggregation"
  }
FUNÇÃO DE AGRUPAMENTO

• Agrupamento:
  db.test.group(
    { cond: {"invoked_at.d": {$gte: "2009-11", $lt:
  "2009-12"}}
    , key: {http_action: true}
    , initial: {count: 0, total_time:0}
    , reduce: function(doc, out){ out.count++;
  out.total_time+=doc.response_time }
    , finalize: function(out){ out.avg_time =
  out.total_time / out.count }
  } )
FUNÇÃO DE AGRUPAMENTO

• Retorno do agrupamento:
  [
    {
      "http_action" : "GET /display/DOCS/
  Aggregation",
      "count" : 1,
      "total_time" : 0.05,
      "avg_time" : 0.05
    }
  ]
MAP/REDUCE
1   1   2

1   1   1

1   1   2

1   1   1

1   1

1   1
4

3

7

4
BANCO DE DADOS
db.items.insert({tags: ['dog', 'cat']})

db.items.insert({tags: ['dog']})

db.items.insert({tags: ['dog', 'mouse']})

db.items.insert({tags: ['dog', 'mouse', 'hippo']})

db.items.insert({tags: ['dog', 'mouse', 'hippo']})

db.items.insert({tags: ['dog', 'hippo']})
MAP

var map = function() {

    this.tags.forEach(function(t) {

         emit(t, {count: 1})

    })

}
REDUCE
var reduce = function(key, val) {

    var count = 0;

    for(var i = 0, len = val.length; i < len; i++) {

        count += val[i].count

    }

    return { count: count };

}
EXECUTANDO



var result = db.items.mapReduce(map, reduce);
RESULTADO
{
	   "result" : "tmp.mr.mapreduce_1286209644_2",
	   "timeMillis" : 30,
	   "counts" : {
	   	    "input" : 6,
	   	    "emit" : 13,
	   	    "output" : 4
	   },
	   "ok" : 1,
}
RESULTADO (MESMO!)



db["tmp.mr.mapreduce_1286209644_2"].find()

db[result['result']].find()
MAP/REDUCE


{ "_id" : "cat", "value" : { "count" : 1 } }

{ "_id" : "dog", "value" : { "count" : 6 } }

{ "_id" : "hippo", "value" : { "count" : 3 } }

{ "_id" : "mouse", "value" : { "count" : 3 } }
OPERAÇÕES ATÔMICAS
OPERAÇÕES ATÔMICAS

• Incrementando com $inc
  db.artigos.update(
     { _id : new ObjectId("4c041...")},
     { $inc: {"hits": 1} }
  )

• Atualizando:
  db.posts.update({}, { $set : { "hits" : 0 }})
ÍNDICES
ÍNDICES

• Desempenho      lento para escrita, mas muito mais rápida para
 leitura

• Para   melhores resultados, crie índices por onde você busca

• MongoDB     mantém índices em memória
SEM ÍNDICE
db.items.find({tags: "dog"}).explain();
{
	    "cursor" : "BasicCursor",
	    "nscanned" : 6,
	    "nscannedObjects" : 6,

	    "n" : 6,
	    "millis" : 10,
	    "indexBounds" : {
	    	

	    }
}
APLICANDO O ÍNDICE



db.items.ensureIndex({tags: 1})
COM ÍNDICE
db.items.find({tags: "dog"}).explain();
{

	     "cursor" : "BtreeCursor tags_1",
	     "nscanned" : 6,
	     "nscannedObjects" : 6,

	     "n" : 6,
	     "millis" : 0,

	     "indexBounds" : {
	     	    "tags" : [
	     	    	     [

	     	    	     	    "dog",
	     	    	     	    "dog"

	     	    	     ]
	     	    ]
	     }

}
GEOPOSICIONAMENTO
GEOPOSICIONAMENTO


• Geoposicionamento, com   MongoDB, é estupidamente
 simples

• Apenas adicione um índice:
  db.lugares.ensureIndex({ localizacao: "2d" })
LUGARES MAIS PERTO


 db.lugares.find({

      localizacao: { $near : [

           21.123456789, -20.123456789

      ]}

 })
20 LUGARES MAIS PERTO


  db.lugares.find({

    localizacao: { $near : [

         21.123456789, -20.123456789

    ]}

  }).limit(20)
EM UMA ÁREA
EM UMA ÁREA
db.lugares.find({

     localizacao: { $within: { $box: {

       [

           [21.123456789, -20.123456789],

           [22.123456789, -21.123456789]

       ]

     }}}

})
POR ONDE CONTINUAR?
WWW.MONGODB.ORG
MONGODB
THE DEFINITIVE GUIDE
REFERÊNCIAS
REFERÊNCIAS
OBRIGADO!


            Júlio Monteiro
        julio@monteiro.eti.br

MongoDB: um banco de dados orientado a documento

  • 1.
  • 2.
    /ME Rails Developer, JobScore(http://www.jobscore.com)
  • 3.
  • 4.
    AGENDA 1. Objetivo 2. Histórico 3.Características 4. Relacional versus MongoDB 5. Consultas 6. Map/reduce 7. Operações atômicas 8. Índices 9. Geoposicionamento 10.Por onde continuar?
  • 5.
    OBJETIVO MongoDB busca aproveitar vantagens de armazenamentos de chave-valor (que, no geral, são rápidos e escaláveis) e banco de dados relacionais tradicionais (que, no geral, oferecem consultas ricas e várias funcionalidades). (Adaptado do site oficial do MongoDB)
  • 6.
    Quando Chuck Norrisfala, todos ficam em silêncio. E morrem.
  • 7.
    HISTÓRICO • Produto da 10gen • Desenvolvimento iniciou em Outubro de 2007 • Primeira versão pública em Fevereiro de 2009 • Atualmente na versão 1.6 • Licenciado sob a GNU AGPL
  • 8.
    CARACTERÍSTICAS (1/2) • Armazenamento orientado a documentos • Índices • Consultas ricas (rich queries) • Atualizações in-place rápidas • Map/Reduce
  • 9.
    CARACTERÍSTICAS (2/2) • Replicação e Alta Disponibilidade • Auto-Sharding • GridFS • Suporte Comercial (da 10gen)
  • 10.
  • 11.
    TABELA id nome sobrenome idade 1 Ana Silva 20 2 Maria Carvalho 22 3 João Chaves 21 4 Mário Schimitd 30 ... ... ... ...
  • 12.
    DOCUMENTO Id: 1 Id: 2 Nome: Ana Nome: Maria Sobrenome: Silva Sobrenome: Carvalho Idade: 20 Idade: 22 Id: 3 Id: 4 Nome: João Nome: Mário Sobrenome: Chaves Sobrenome: Schimitd Idade: 21 Idade: 30
  • 13.
    TERMINOLOGIA Relacional Tradicional MongoDB (MySQL, PostgreSQL, etc) Database Database (Banco de dados) (Banco de dados) Table Collection (Tabela) (Coleção) Row Document (Linha, registro) (Documento) Column Attribute (Coluna) (Atributo)
  • 14.
    MODELO ENTIDADE- RELACIONAMENTO MYSQL artigos comentarios artigos_palavras_chave palavras_chave
  • 15.
    MODELO ENTIDADE MONGODB comentarios artigos palavras_chave
  • 16.
    DOCUMENTO EM { MONGODB "_id" : ObjectID("4c03e856e258c2701930c091"), "titulo" : "Campus Party Brasil 2011 vêm aí", "atalho" : "campus-party-brasil-2011-vem-ai", "texto" : "A Campus Party Brasil 2011 está chegando, e com elas diversas atrações!", "publicado" : true, "criado_em" : "Mon Oct 4 2010 16:00:00 GMT-0300 (BRT)", "atualizado_em" : "Mon Oct 4 2010 16:00:00 GMT-0300 (BRT)", "comentarios" : [ { "autor" : "Julio", "email" : "julio@monteiro.eti.br", "conteudo" : "Gostei muito da Campus!", "criado_em" : "Mon Oct 4 2010 17:00:00 GMT-0300 (BRT)" } ], "palavras_chave" : [ "cpbr4", "campus", "party" ] }
  • 17.
  • 18.
    BJSON Bin ary JavaScriptObject Notation
  • 21.
  • 22.
    COMO BUSCO... • ...por uma palavra inteira? db.artigos.find({"titulo" : "campus"}) • ... por parte de uma palavra? db.artigos.find({"titulo" : /campus/i}) • ... por uma palavra dentro de um array? db.artigos.find({"palavras_chave" : "campus"}) • ... por uma palavra dentro de um embutido? db.artigos.find({ "comentarios.email" : "julio@monteiro.eti.br" })
  • 23.
    COMO ATUALIZO... ... determinadoatributo de um registro? db.artigos.update( { "comentarios.email" : "julio@monteiro.eti.br" }, { $set: { "comentarios.$.email" : "julio@awegen.com" } } )
  • 24.
  • 25.
    OPERADORES $gt $all $gte $size $lt $exists $lte $type $ne $elemMatch $in $not $nin $where $mod
  • 26.
    USANDO OPERADORES • Maiorque ($gt): terceiraIdade = db.pessoas.find({ "age": { $gt: 75 } }) • Incluindo ($in): interessante = db.artigos.find({ "tags" : { $in : ["mongodb", "interessante"] } }) • Não incluindo ($nin): todo = db.tarefas.find({ "status" : { $nin : [ "em execucao", "terminado" ] } })
  • 27.
    FUNÇÕES ARBITRÁRIAS • Usandofunções arbitrárias (com $where): db.artigos.find({ $where : function() { return this.acessos % 2 == 0 } }) • Usando agrupamento (com $group): db.artigos.group({ "key" : { "hits" : true }, "initial" : { "count": 0 }, "reduce" : function(obj, prev) { prev.count++; } })
  • 28.
    FUNÇÃO DE AGRUPAMENTO •Dado que possui documentos como... { domain: "www.mongodb.org", invoked_at: {d:"2009-11-03", t:"17:14:05"}, response_time: 0.05, http_action: "GET /display/DOCS/Aggregation" }
  • 29.
    FUNÇÃO DE AGRUPAMENTO •Agrupamento: db.test.group( { cond: {"invoked_at.d": {$gte: "2009-11", $lt: "2009-12"}} , key: {http_action: true} , initial: {count: 0, total_time:0} , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } , finalize: function(out){ out.avg_time = out.total_time / out.count } } )
  • 30.
    FUNÇÃO DE AGRUPAMENTO •Retorno do agrupamento: [ { "http_action" : "GET /display/DOCS/ Aggregation", "count" : 1, "total_time" : 0.05, "avg_time" : 0.05 } ]
  • 31.
  • 34.
    1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 1
  • 35.
  • 36.
    BANCO DE DADOS db.items.insert({tags:['dog', 'cat']}) db.items.insert({tags: ['dog']}) db.items.insert({tags: ['dog', 'mouse']}) db.items.insert({tags: ['dog', 'mouse', 'hippo']}) db.items.insert({tags: ['dog', 'mouse', 'hippo']}) db.items.insert({tags: ['dog', 'hippo']})
  • 37.
    MAP var map =function() { this.tags.forEach(function(t) { emit(t, {count: 1}) }) }
  • 38.
    REDUCE var reduce =function(key, val) { var count = 0; for(var i = 0, len = val.length; i < len; i++) { count += val[i].count } return { count: count }; }
  • 39.
    EXECUTANDO var result =db.items.mapReduce(map, reduce);
  • 40.
    RESULTADO { "result" : "tmp.mr.mapreduce_1286209644_2", "timeMillis" : 30, "counts" : { "input" : 6, "emit" : 13, "output" : 4 }, "ok" : 1, }
  • 41.
  • 42.
    MAP/REDUCE { "_id" :"cat", "value" : { "count" : 1 } } { "_id" : "dog", "value" : { "count" : 6 } } { "_id" : "hippo", "value" : { "count" : 3 } } { "_id" : "mouse", "value" : { "count" : 3 } }
  • 43.
  • 44.
    OPERAÇÕES ATÔMICAS • Incrementandocom $inc db.artigos.update( { _id : new ObjectId("4c041...")}, { $inc: {"hits": 1} } ) • Atualizando: db.posts.update({}, { $set : { "hits" : 0 }})
  • 45.
  • 46.
    ÍNDICES • Desempenho lento para escrita, mas muito mais rápida para leitura • Para melhores resultados, crie índices por onde você busca • MongoDB mantém índices em memória
  • 47.
    SEM ÍNDICE db.items.find({tags: "dog"}).explain(); { "cursor" : "BasicCursor", "nscanned" : 6, "nscannedObjects" : 6, "n" : 6, "millis" : 10, "indexBounds" : { } }
  • 48.
  • 49.
    COM ÍNDICE db.items.find({tags: "dog"}).explain(); { "cursor" : "BtreeCursor tags_1", "nscanned" : 6, "nscannedObjects" : 6, "n" : 6, "millis" : 0, "indexBounds" : { "tags" : [ [ "dog", "dog" ] ] } }
  • 50.
  • 51.
    GEOPOSICIONAMENTO • Geoposicionamento, com MongoDB, é estupidamente simples • Apenas adicione um índice: db.lugares.ensureIndex({ localizacao: "2d" })
  • 52.
    LUGARES MAIS PERTO db.lugares.find({ localizacao: { $near : [ 21.123456789, -20.123456789 ]} })
  • 53.
    20 LUGARES MAISPERTO db.lugares.find({ localizacao: { $near : [ 21.123456789, -20.123456789 ]} }).limit(20)
  • 54.
  • 55.
    EM UMA ÁREA db.lugares.find({ localizacao: { $within: { $box: { [ [21.123456789, -20.123456789], [22.123456789, -21.123456789] ] }}} })
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
    OBRIGADO! Júlio Monteiro julio@monteiro.eti.br