MongoDB

la base NoSQL qui réinvente la gestion de données

11/28/13

@dwursteisen

!1
MongoDB
Big Database
@DWURSTEISEN
http://fr.slideshare.net/soatexpert
WARNING
Il n’y a pas si longtemps que cela,
un site internet faisait sensation…
20:00:00
Ce site déboite
Oups ! Database Error
no more space disk available
IG
B

TA
A
D
oat
nS
tio
ima
An
013
ce 2
ran
xF
vox
De
Caractéristiques
(sous le capot)
Orienté document
{!

}

!
"enigme1",
!
"_id":
v e n d r e d i ",
du
e": "Enigme
"titr
e!
a t i o n ": t r u
"activ
{!

!
"enigme1",
!
"_id":
v e n d r e d i ",
du
e": "Enigme
"titr
e!
a t i o n ": t r u
"activ

}

{!

}!

"_id": "enig
me1", !
"activation"
: true, !
"joueurs": [
!
{ "email": "
john@doe.com
], !
", " s c o r e ":
20 }!
"indices": [
!
{!
"contenu": "
je suis ton
p è r e ", !
" f l a s h c o d e ":
"111-111-111
1 ", !
"joueurs": [
{ "email": "
}
john@doe.com
]!
" } ]!
Sans schéma
CREATE TABLE example_default_now (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
data VARCHAR(100),
created TIMESTAMP DEFAULT NOW()
);
CREATE TABLE example_default_now (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
data VARCHAR(100),
created TIMESTAMP DEFAULT NOW()
);
Sans transaction
Transaction
Transaction
Transaction
Transaction
Transaction
Transaction
Sans transaction
Sans transaction
Sans transaction
Sans transaction
Update atomique
Sans jointure
{!

}!

"_id": "enig
me1", !
"activation"
: true, !
"joueurs": [
!
{ "email": "
john@doe.com
], !
", " s c o r e ":
20 }!
"indices": [
!
{!
"contenu": "
je suis ton
p è r e ", !
" f l a s h c o d e ":
"111-111-111
1 ", !
"joueurs": [
{ "email": "
}
john@doe.com
]!
" } ]!
{!

}!

"_id": "enig
me1", !
"activation"
: true, !
"joueurs": [
!
{ "email": "
john@doe.com
], !
", " s c o r e ":
20 }!
"indices": [
!
{!
"contenu": "
je suis ton
p è r e ", !
" f l a s h c o d e ":
"111-111-111
1 ", !
"joueurs": [
{ "email": "
}
john@doe.com
]!
" } ]!

jointure ?
Distribué
Document = 16Mb Hard Limit
Design
des structures
des données
Type

Exemple

Int / Double / …

{ a: 1 }

Boolean

{ b: true }

String

{ c: ‘hello’ }

Array

{ d: [1, 2, 3] }

Date

{e: ISODate("2012-12-19T06:01:17.171Z")

ObjectId

{f: ObjectId(‘123456’)}

Object

{g: {a: 1, b: true}}

…

http://docs.mongodb.org/manual/reference/bson-types/
Organiser
les données selon leurs

Utilisations
ci gît la 

4ème forme 

normale
Question :

Structure de donnée pour
l’affichage d’un message ?
2
Auteur

2
Auteur

2

Contenu
Auteur

Contenu

2

Recouicoui
{
_id: ObjectId(11),
{
_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
{
_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
{
_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
{
_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: [ObjectId(22), ObjectId(33)] 
{

!

_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: 2, // compteur
{

!

_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: [{user: {…}, {user: {…}]
{

!

_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: [{user: {…}, {user: {…}]
{

!

_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: [{user: {…} * 789013]
{

!

_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: [{user: {…} * 789013]

> 16Mb
2
2

Information partielle
{
_id: ObjectId(11),
user: {mail: « user1 », avatar: « http://…. »,
content: « blabla »,
…
recouicoui: {
users: [{user: {…} * 5],
compteur: 789013
}
Le design d’une

bonne
complexe

structure de donnée est
Query language

s
u
o
v
z
e
l
?
r
a
s
i
P
a
ç
n
a
r
F

select * from table
Le shell : mongo
Lecture
Sélection d’un document

db.collection.findOne(…)
Query
Sélection d’un document

db.collection.findOne(…)
Sélection de documents

db.collection.find(…)
Sélection et mise à jour de document

db.collection.findAndModify(…)
Champ unique

{_id: ‘azerty’}
Champ unique

{_id: ‘azerty’}
{!

"_id": "azerty", !
"titre": "Enigme du vendredi", !
"activation": true!
}

✓
Champ unique

{_id: ‘azerty’}
{!

"_id": "azerty", !
"titre": "Enigme du vendredi", !
"activation": true!

✓

"_id": "azerty", !
"activation": true,!
"titre": "Enigme du vendredi"!

✓

}

{!

}
Champ unique

{_id: ‘azerty’}
{!

"_id": "azerty", !
"titre": "Enigme du vendredi", !
"activation": true!

✓

"_id": "azerty", !
"activation": true,!
"titre": "Enigme du vendredi"!

✓

"_id": "azerty12345", !
"activation": true,!
"titre": "Enigme du vendredi"!

✗

}

{!

}
{!

}
Sous document spécifique

{auteur: {nom: ‘Wursteisen’}}
Sous document spécifique

{auteur: {nom: ‘Wursteisen’}}
{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen"}!
}

✓
Sous document spécifique

{auteur: {nom: ‘Wursteisen’}}
{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen"}!
}

✓

{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen", "prénom":"David"}!
}

✗
Sous document spécifique

{auteur: {prénom: ‘David’, nom: ‘Wursteisen’}}
Sous document spécifique

{auteur: {prénom: ‘David’, nom: ‘Wursteisen’}}
{!
"_id": "azerty", !
"auteur": {"prénom":"David", "nom":"Wursteisen"}!
}

✓
Sous document spécifique

{auteur: {prénom: ‘David’, nom: ‘Wursteisen’}}
{!
"_id": "azerty", !
"auteur": {"prénom":"David", "nom":"Wursteisen"}!
}

✓

{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen", "prénom":"David"}!
}

✗
Sous champ

{‘auteur.nom’: ‘Wursteisen’}
Sous champ

{‘auteur.nom’: ‘Wursteisen’}
{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen"}!
}

✓
Sous champ

{‘auteur.nom’: ‘Wursteisen’}
{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen"}!
}

✓

{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen", "prénom":"David"}!
}

✓
Sous champ

{‘auteur.nom’: ‘Wursteisen’}
{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen"}!
}

✓

{!
"_id": "azerty", !
"auteur": {"nom":"Wursteisen", "prénom":"David"}!

✓

}
{!
"_id": "azerty", !
"auteur": {"nom":"Bob", "prénom":"David"}!
}

✗
Champ unique

{recouicoui: {$gt: 20}}
Champ unique

{recouicoui: {$gt: 20}}
{!
"_id": "azerty", !
"titre": "Enigme du vendredi", !
"recouicoui": 50!
}

✓
Champ unique

{recouicoui: {$gt: 20}}
{!
"_id": "azerty", !
"titre": "Enigme du vendredi", !
"recouicoui": 50!

✓

"_id": "azerty", !
"titre": "Enigme du vendredi", !
"recouicoui": 10!

✗

}
{!

}
Champ unique

{recouicoui: {$gt: 20}}
{!
"_id": "azerty", !
"titre": "Enigme du vendredi", !
"recouicoui": 50!

✓

"_id": "azerty", !
"titre": "Enigme du vendredi", !
"recouicoui": 10!

✗

"_id": "azerty", !
"titre": "Enigme du vendredi", !

✗

}
{!

}
{!

!
}
Écriture
Insertion d’un document

db.collection.insert(…)
Insertion d’un document

db.collection.insert(…)

Document
Update d’un document

db.collection.update(<query>, <update>)
Update d’un document

db.collection.update(<query>, <update>)

modifier
Update de documents

db.collection.update(…, …, {multi: true})
Écrire un document

db.collection.update(…, {prénom:’David’})
Écrire un document

db.collection.update(…, {prénom:’David’})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"prénom": "bob"!
}
Écrire un document

db.collection.update(…, {prénom:’David’})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"prénom": "bob"!
}

{!
"_id": "azerty", !
"prénom": "David"!
}
Modifier un champ

db.collection.update(…, {$set: {prénom:’David’}})
Modifier un champ

db.collection.update(…, {$set: {prénom:’David’}})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"prénom": "bob"!
}
Modifier un champ

db.collection.update(…, {$set: {prénom:’David’}})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"prénom": "bob"!
}

{!
"_id": "azerty", !
"nom": "wursteisen", !
"prénom": "David"!
}
Incrémentation

db.collection.update(…, {$inc: {recouicoui: 2 }})
Incrémentation

db.collection.update(…, {$inc: {recouicoui: 2 }})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"recouicoui": 5!
}
Incrémentation

db.collection.update(…, {$inc: {recouicoui: 2 }})
{!
"_id": "azerty", !
"nom": "wursteisen", !
"recouicoui": 5!
}

{!
"_id": "azerty", !
"nom": "wursteisen", !
"recouicoui": 7!
}
Ajout dans un tableau

db.collection.update(…, {$push: {contact: ‘Robert’ }})
Ajout dans un tableau

db.collection.update(…, {$push: {contact: ‘Robert’ }})
{!
"_id": "azerty", !
"contact": ["John", "Bob"]
}

!
Ajout dans un tableau

db.collection.update(…, {$push: {contact: ‘Robert’ }})
{!
"_id": "azerty", !
"contact": ["John", "Bob"]

!

}

{!
"_id": "azerty", !
"contact": ["John", "Bob", "Robert"]
}

!
Index
Index simple

db.couicoui.ensureIndex({ name:1 })
Index composé

db.couicoui.ensureIndex({ name:1, date:-1 })
Géo index

db.couicoui.ensureIndex({ geo: ‘2d‘ })
Index avec Time To Live

db.couicoui.ensureIndex({ name:1 }, {expireAfterSeconds: 3600})
db.find({…}).explain()
{
"cursor" : "<Cursor Type and Index>",
"n" : <num>,
"nscanned" : <num>,
"scanAndOrder" : <boolean>,
…
}
Replica Set
Driver
Primary
Secondary

Secondary
Driver
Écriture
Primary
Secondary

Secondary
Driver
Écriture
Primary
Réplication
Secondary

Secondary
Driver
Écriture
Primary
Réplication
Secondary

Réplication
Secondary
Driver
Écriture
Primary
Réplication
Secondary

Lecture
Réplication
Secondary
Lecture

Driver
Écriture
Primary

Réplication
Secondary

Lecture
Réplication
Secondary
Primary
Secondary

Secondary
Primary
Heartbeats
Secondary

Secondary
Primary
Heartbeats
Secondary

Secondary
Primary
Secondary

Secondary
Primary
Secondary

Secondary
Primary ?
Primary
Primary

Secondary
Primary ?
Réplication

Primary

Primary

Secondary
Primary ?
Réplication

Primary

Primary

Secondary
Primary ?
Réplication

Primary
Heartbeats

Primary

Secondary
Primary ?
Réplication

Primary
Heartbeats

Primary

Secondary
Primary ?
Réplication

Secondary
Heartbeats

Primary

Secondary
Primary ?
Réplication

Secondary
Heartbeats

Primary

Secondary
Primary ?
Write Concern
notification d’écriture
collection.insert(…, WriteConcern.ACKNOWLEDGED);
!

db.getLastError();

(dépendant du driver)
w=1
collection.insert(…, WriteConcern.ACKNOWLEDGED);
!

db.getLastError();

(dépendant du driver)
w=1
collection.insert(…, WriteConcern.ACKNOWLEDGED);
!

db.getLastError();

bloquant
(dépendant du driver)
disable acknowledgment
w=0
Driver

Mongod
Driver

write
Mongod
write
Mongod

getLastError

w=0

Driver
getLastError
response

write
Mongod

getLastError

w=0

Driver
acknowledgment
w=1
Driver

Mongod
Driver

write
Mongod
write
Mongod

getLastError

w=1

Driver
write

getLastError

w=1

Driver

Mongod

apply
Mongod

apply

getLastError
response

write

getLastError

w=1

Driver
bloquant

Mongod

apply

getLastError
response

write

getLastError

w=1

Driver
journal
j=1
Driver

Mongod
Driver

write
Mongod
write
Mongod

getLastError

w=1,j=1

Driver
write

getLastError

w=1,j=1

Driver

Mongod

apply
write

getLastError

w=1,j=1

Driver

Mongod

apply

write to
journal
write to
journal

apply

getLastError
response

write

getLastError

w=1,j=1

Driver

Mongod
bloquant

write to
journal

apply

getLastError
response

write

getLastError

w=1,j=1

Driver

Mongod
replica acknowledgment
w=2
Driver

Primary

Secondary
Secondary
Driver

write
Primary

Secondary
Secondary
write
Primary

Secondary
Secondary

getLastError

w=2

Driver
write

getLastError

w=2

Driver

Primary

apply
Secondary
Secondary
write

getLastError

w=2

Driver

apply
Secondary
Secondary

replicate

Primary
write

getLastError

w=2

Driver

apply
Secondary
Secondary

replicate

Primary
apply

Secondary

replicate

Primary

getLastError
response

write
Secondary

getLastError

w=2

Driver
apply

Secondary

replicate

Primary

getLastError
response

Driver

getLastError

w=2

write
Secondary

bloquant
Secondary

replicate

apply

replicate

Primary

getLastError
response

Driver

getLastError

w=2

write
Secondary

bloquant
Sharding

Répartition
collection
collection

Shard1

Shard2

Shard3
collection

Shard1
{x: min}

Shard2
{x: -11}

Shard3
{x: 50}

{x: max}
Avec une clé de sharding
db.collect.find({key: …})
Mongos
db.collect.find({key: …})
Mongos
db.collect.find({key: …})
Mongos
db.collect.find({key: …})
Mongos
db.collect.find({key: …})
Mongos
Avec une clé non shardé
db.collect.find({other: …})
Mongos
db.collect.find({other: …})
Mongos
db.collect.find({other: …})
Mongos
Question :

Clé de sharding pour gérer 

les messages d’un utilisateur ?
Répartition
Cardinalité
Isolation
en écriture
_id

Fiabilité
ObjectId(« 507f1f77bcf86cd799439011 »)

http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Timestamp
ObjectId(« 507f1f77bcf86cd799439011 »)

http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Timestamp
ObjectId(« 507f1f77bcf86cd799439011 »)

Host
http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Timestamp

PID

ObjectId(« 507f1f77bcf86cd799439011 »)

Host
http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Timestamp

PID

ObjectId(« 507f1f77bcf86cd799439011 »)

Host

Compteur

http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Timestamp
ObjectId(« 507f1f77bcf86cd799439011 »)

http://www.mongodb.com/presentations/advanced-sharding-features-mongodb-24
Répartition
Cardinalité
Isolation
en écriture
_id

✓ ✗

✗

Fiabilité

✗
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
Répartition
Cardinalité
Isolation
en écriture
_id
hash(_id)

Fiabilité

✓ ✗ ✗
✓ ✓ ✗

✗
✗
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
Répartition
Cardinalité
Isolation
en écriture
_id
hash(_id)
user

Fiabilité

✓ ✗ ✗ ✗
✓ ✓ ✗ ✗
✗ ✓ ✓ ✓
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
Répartition
Cardinalité
Isolation
en écriture
_id
hash(_id)
user
user, time

✓
✓
✗
✓

✗
✓
✓
✓

✗
✗
✓
✓

Fiabilité

✗
✗
✓
✓
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.insert({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
db.collect.find({…})
Mongos
Aller plus loin…
https://education.mongodb.com
http://www.meetup.com/Paris-MongoDB-User-Group/
Demo
https://github.com/dwursteisen/atelier-mongodb
Questions ?
@dwursteisen
Crédits photos
http://bit.ly/HNvkfZ
http://bit.ly/1hTARzS

http://bit.ly/HGb1BO

http://bit.ly/1hrvZ7z
http://bit.ly/1d5OVTr

http://bit.ly/17SGXwC

http://bit.ly/1awf0XL

http://bit.ly/HNvRP4
http://bit.ly/MMaRr8
http://bit.ly/HGf2Gh

http://bit.ly/1967kv2

http://bit.ly/1c6uCUA

MongoDB : la base NoSQL qui réinvente la gestion de données