samedi 21 juin 2014

Opérations avancées avec MongoDB

Dans une video, j'avais présenté une introduction à MongoDB.

Pour faire une suite voici quelques manipulations avec le client mongo ou  l'API Ruby.



Pour commencer: 

Avec le client mongo :
voir toutes les bases : shows dbs 
voir toutes les collections d'une base: show collections

Pour les recherches :


Rechercher à l'aide d'une expression régulière :ATTENTION à réserver que pour les champs 'string'
Toutes les stations de velib dont l'adresse contient le mot 'filles' (ex filles du calvaire )
db.stations.find({address :/.+filles.+/i}).count()

ou en version moins compacte :
db.stations.find({address : $regex :{/.+filles.+/i}}).count()

Pour inverser la sélection : $regex :{/(?!.+filles.+)/i}

Avec l'API Ruby:
rech = @stations.find({:address => /#{Regexp.quote(arr)}/}).each { |p| ...


Rechercher les entrées avec qui n'ont pas un champs précis:
db.stations.find({rem: {$exists : false}})

ou 

db.stations.find({rem: null})  # cette forme ne fonctionne pas si un champs contient la valeur null

Avec l'API Ruby:

rech = @stations.find({:arrondissement => nil})....

Afficher que certain champs en sortie:

db.stations.find({arrondissement: 75001},{'state.total_slots' : 1})

Avec Ruby : utiliser le symbole :fields :


@pgm = @db['jcl'].find({'source' => {'$exists' => true}},{:fields => {'jcl' => 1 , 'source' => 1, '_id' => 0}} ).to_a

(le champs id ou _id est special ,c'est l'identifiant des entrées.  il est toujours retourné sauf si , la valeur de sa clé est mise  à zero.)

Une recherche avec une  condition qui porte sur  deux champs de l'entrée (utilisation de $where et this.
(API Ruby)

@alerte = @coll.find('$where'  => "this.reel['total moe'] >= this.valide['total moe']" , 'semaine' => semaine )

Enfin: un tri
db.stations.find({},{address:1}).sort({'state.total_slots' :-1 }).limit(1)
Ici , le tri combiné à   limit(1) permet de récupérer la valeur la plus grande.

Regroupement d'entrée: 


  • Le plus simple est l'opérateur distinct:

db.stations.distinct('arrondissement')

distinct retourne un array (tableau) , aussi pour connaitre le nombre d élément:
db.stations.distinct('arrondissement').length  



  • L'operateur group:


Un autre manière de déterminer le maxima d'une série

@arr = @coll.group( :initial => {cmax:0} ,:reduce =>  "function(obj,prev) { if(prev.cmax < obj.semaine) prev.cmax = obj.semaine; }" )

un autre exemple avec le client mongo
db.stations.group({initial : {cmax : 0 } ,reduce : function(obj,prev) { if (obj.state.total_slots > prev.cmax) prev.cmax = obj.state.total_slots }})

[ { "cmax" : 72 } ]

Enfin un exemple de regroupement avec cumul intermédiaire et condition :

esi  =@coll.group(:key => :esi ,
                       :reduce => "function(obj,res) {res.pr.push({projet :obj['projet'],v: obj['valide']          ['moed'], r:obj['reel']['moed']  });
                                    res.valideESI += obj['valide']['moed'] ;  
                                    res.reelESI += obj['reel']['moed'] ; }",
                        :initial => {  :pr =>  [],
                                       :valideESI => 0,
                                       :reelESI   => 0 
                         },
                       :cond => {:semaine => max})


Aucun commentaire: