Outils pour utilisateurs

Outils du site


bases_de_donnees:mongodb:toc

MongoDB

MongoDB est une base de donnée non-relationnelle (NoSQL) stockant des documents en BSON.

Concepts

Dans les bases de données relationnelles, on a des bases de données, des tables, des colonnes, etc. Dans une base de données NoSQL, on a aussi des bases de données, mais ce sont plutôt des collections, des documents et des propriétés.

Ensemble de réplication

Client mongo

Le client MongoDB est simplement mongo. Pour changer de base de données, on utilise use {database_name}. La commande use va créer la base de données si elle n'existe pas. Pour savoir sur quelle DB on travaille, on tape simplement db.

MongoDB shell version: 2.6.5
connecting to: test
> use foo
switched to db foo
> db
foo

Pour de l'aide: help.

Pour voir les collections : show collections.

Enregistrer des données

Les données sont sauvegardées en BSON1).

Règles

La seule règle qui existe est que le document doit avoir un champ _id. S'il n'est pas fourni par l'application, MongoDB en assignera un avec un GUID.

Types de données

Pour les _id, le type de données peut être :

  • Integer : db.foo.save({_id: 1})
  • Float : db.foo.save({_id: 3.14})
  • String : db.foo.save({_id: "Hello"})
  • Date : db.foo.save({_id: ISODate()})
  • Objet : db.foo.save({_id: { a: 'x', b:2 } })

Le _id ne peut pas être un tableau.

ObjectId()

> ObjectId()
ObjectId("5493947978a8ebfad5f7a598")
> ObjectId().getTimestamp()
ISODate("2014-12-19T03:07:04Z")

Insérer un document

> db.foo.save({_id:1, x:10})
> db.foo.find()
{ "_id" : 1, "x" : 10 }
> show collections
foo
system.indexes

Si on sauvegarde (en utilisant save()) deux documents différents dans la même collection, mais que ceux-ci ont la même valeur _id, le dernier document inséré va écraser le précédent. Si on fait la même chose, mais avec insert(), MongoDB lancera une erreur.

Si on insère deux documents avec les mêmes données, mais sans spécifier le _id, les deux documents seront gardés, en ayant deux _id de type ObjectId différents.

Mise à jour

Update

> db.foo.update(query, update, options);

Incrémenter une valeur:

> db.a.update({_id:1}, {$inc: {x:1}})

Changer une valeur:

> db.a.update({_id:1}, {$set: {x:1}})

Le unset permet d'enlever une propriété. On spécifie une valeur à la propriété, mais elle n'a pas d'importance, le résultat c'est qu'il n'y aura plus de propriété x à l'objet ayant le _id 1 :

> db.a.update({_id:1}, {$unset: {x: 1}})
> db.a.update({_id:1}, {$unset: {x: ''}})

Renommer une propriété, dans ce cas-ci on renomme la propriété 'Naem' à 'Name' :

> db.a.update({_id:1}, {$rename: {'Naem': 'Name'}})

$push ajoute des éléments à un tableau :

> db.a.update({_id:1}, {$push: {x: 1}})
> db.a.update({}, {$push: {x: 1}}, {multi:true})

$addToSet ajoute des éléments à un tableau en ne permettant pas les doublons (set ou ensemble).

$pop enlève le dernier élément d'un array. Pour enlever le premier élément, il faut utiliser -1.

> db.a.update({_id:1}, {$pop: {x: 1}})
> db.a.update({_id:1}, {$pop: {x: -1}})

FindAndModify

Signature de la méthode:

db.foo.findAndModify({
  query: <document>,
  update: <document>,
  remove: <boolean>,
  new: <boolean>,
  sort: <document>,
  fields: <document>
});

Trouver des données

Requêtes

La méthode find() a deux paramètres. La première query détermine les quels documents seront retournés et projection spécifie qu'elle partie des documents sont voulus.

find(query[, projection])

Par exemple, si on veut les documents ayant le _id à 1:

> db.animals.find({_id: 1})

Ceci retourne par exemple :

{ "_id" : 1, "name" : "cat", "tags" : [ "land", "cute" ], "info" : { "type" : "mammal", "color" : "red" } }

Si on veut utiliser la projection :

> db.animals.find({_id: 1}, {_id:1})
{ "_id" : 1 }

Sensible à la casse

Les propriétés ainsi que les valeurs sont sensibles à la casse. Donc, la requête db.foo.find({"name" : "Joe"}) n'est pas la même que db.foo.find({"name" : "joe"}) ou db.foo.find({"Name" : "Joe"}).

Dot notation

Les documents peuvent imbriquer d'autres documents. Si par exemple pour un document nous avons les propriété name et info, mais que info est un document ayant les propriétés type et color, on peut utiliser la notation de points :

> db.foo.find({"info.type": "animal"})
> db.foo.find({"info.color": "red"})

Plus grand que / Plus petit que

Les documents dont le id est plus grand que (gt), plus petit que (lt), plus grand que et égal (gte) et plus petit que et égal à 5:

> db.animals.find({_id: {$gt:5 }})
> db.animals.find({_id: {$lt:5 }})
> db.animals.find({_id: {$gte:5 }})
> db.animals.find({_id: {$lte:5 }})

On peut spécifier un range :

> db.animals.find({_id: {$gt:5, $lte:10 }})

Documentation MongoDB:

Opérateur $not

Les items qui n'ont pas de id plus grand que 5:

> db.animals.find({_id: {$not: {$gt:5 }}})

Opérateur $not

Opérateur $in

On trouve les documents qui sont inclus dans les valeurs spécifiés avec l'opérateur $in. Par exemple, ici on veut les id qui sont inclus dans le tableau [1,3], c'est-à-dire que les documents ayant comme id 1 et 3 seront retournés. Si on veut la négation de $in, on utilise $nin (not in).

> db.animals.find({_id: {$in: [1,3]}})
> db.animals.find({_id: {$nin: [1,3]}})

Opérateur $in

Opérateur $all

On veut trouver les documents qui ont une propriété qui a tous les éléments. Par exemple, si une propriété tags contient un tableau d'éléments et qu'on veut matcher deux de ces éléments, on fait :

> db.animals.find({tags: {$all: ['cute, 'ocean']}})

Utiliser l'opérateur $all, c'est comme utiliser un et parmi les éléments : le document doit avoir le tag cute et ocean. Contrairement à $in où l'on dirait : le document doit avoir le tag cute ou ocean.

Opérateur $exists

L'opérateur $exists permet de sélectionner les documents dont la propriété existe. Par exemple, tous les animaux dont la propriété info.canFly existe s'écrirait :

> db.animals.find({ "info.canFly": {$exists: true} })

sort()

Le tri se fait en spécifiant la propriété sur laquelle on veut trier et le sens : ascendant c'est 1 et descendant c'est -1.

> db.animals.find().sort({_id:-1})

skip()

Permet de sauter des documents. Un skip(10) sauterait les 10 premiers documents.

> db.animals.find().skip(10)

limit()

Permet de limiter le nombre de documents voulus. Un limit(10) revoie 10 document au total.

> db.animals.find().limit(10)

findOne()

Retourne exactement 1 document. Normalement utilisé quand on connait la valeur de _id d'un document.

Indexing

Types d'indexes :

  • Régulier (B-Tree)
  • Geo
  • Text
  • Hashed
  • TTL (Time to Live pour les documents qui ont une durée de vie déterminée)

Créer un index

> db.foo.ensureIndex(keys, options)

Par exemple :

> db.animals.ensureIndex({name:1})

Voir l'utilisation d'un index

Pour voir si un index existe déjà, on peut vérifier sur db.system.indexes.find({ns: 'nom_collection'}, {key:1}).

Pour voir si Mongo a utilisé un index pour retrouver des données, on peut utiliser explain() sur un curseur.

> db.foo.find({name: 'cat'}).explain()

Si dans le document retourné on voit "cursor" : "BasicCursor", cela signifie qu'aucun index a été utilisé. Aussi, nscanned donne le nombre de documents recherchés. Par exemple, sans index ce peut être 6 et avec un index seulement 1.

Supprimer un index

On utilise dropIndex() pour supprimer un index.

> db.animals.dropIndex("name_1")

Unique

Quand on crée un index, on peut spécifier que le champ est unique.

> db.animals.ensureIndex({name:1}, {unique:true})

Autres méthodes utiles

> db.user.find().pretty()

Aggregation Framework

  1. db.runCommand({aggregate: 'MyCollection', … })
  2. db.MyCollection.aggregate(operator1, operator2, …)

Pipeline Architecture

$group

$sum

La fonctionnalité la plus simple de $group est de compter le nombre de documents avec $sum, ce qui revient au même que d'utiliser count() sur la collection.

> db.foo.aggregate( { "$group" : { "_id" : "all", "sum" : { "$sum" : 1 } } } )
{ "result" : [ { "_id" : "all", "sum" : 100 } ], "ok" : 1 }
> db.foo.count()
100

\$avg, $min, $max

Pour les fonctionnalités de moyenne, minimum et maximum, le principe reste pas mal le même.

Quand on veut désigner une propriété, on donne son nom précédé de $. Dans le cas suivant, il s'agit de la propriété qty que l'on désigne par $qty. C'est ce qu'on appelle un value-of-field.

> db.foo.aggregate( { "$group" : { "_id" : "all", "avg" : { "$avg" : "$qty" } } } )
> db.foo.aggregate( { "$group" : { "_id" : "all", "min" : { "$min" : "$qty" } } } )
> db.foo.aggregate( { "$group" : { "_id" : "all", "max" : { "$max" : "$qty" } } } )

On peut utiliser les fonctions $sum, $avg, $min et $max du même coup.

> db.foo.aggregate( { "$group" : { "_id" : "all", "avg" : { "$avg" : "$qty" }, "min" : { "$min" : "$qty" } } } )

Grouper par propriété

Dans les exemples précédents, nous avons utilisé all pour les _id. On peut dire que les _id seront le groupement par une propriété. Par exemple, ayant une collection de ventes et chaque vente ayant un sku et une qty, on peut grouper par sku pour savoir quel produit s'est vendu le plus.

> db.foo.aggregate( { "$group" : { "_id" : "$sku", "sum" : { "$sum" : "$qty" } } } )

On peut utiliser le dot notation avec $group. Si par exemple on a qty qui est sous item, comme ceci :

{ "_id" : 0, "sku" : "U5", "item" : { "qty" : 6, "price" : 5 } }

on peut trouver le minimum en faisant :

> db.foo.aggregate({ "$group" : { "_id" : "$sku", "min" : { "$min" : "$item.qty" } } })

$unwind

$project

$limit

$skip

$sort

$match

Sert de filtre

$geoNear

$addToSet

bases_de_donnees/mongodb/toc.txt · Dernière modification: 2015/10/10 21:44 par sgariepy