MongoDB: Difference between revisions
No edit summary |
|||
| (33 intermediate revisions by the same user not shown) | |||
| Line 2: | Line 2: | ||
* écrit en C++ |
* écrit en C++ |
||
* tolérance aux pannes par réplication ([http://docs.mongodb.org/manual/replication/ replicat set]) |
* tolérance aux pannes par réplication ([http://docs.mongodb.org/manual/replication/ replicat set]) |
||
* passage à l'échelle en distribuant |
* passage à l'échelle (''horizontal scaling'') en distribuant une base de données entre plusieurs processus mongod ([http://docs.mongodb.org/manual/sharding/ sharding], [http://docs.mongodb.org/master/MongoDB-sharding-guide.pdf guide]) |
||
* shell [[Javascript]] ([http://docs.mongodb.org/manual/reference/javascript/ plus ...]) |
* shell [[Javascript]] ([http://docs.mongodb.org/manual/reference/javascript/ plus ...]) |
||
* stockage native des objets [[JSON]] |
* stockage native des objets [[JSON]] |
||
* support de persistance pour les programmes [[Node.js]] ([https://wiki.10gen.com/display/DOCS/node.JS plus ...] et [[Mongoose]]) |
* support de persistance pour les programmes [[Node.js]] ([https://wiki.10gen.com/display/DOCS/node.JS plus ...] et [[Mongoose]]) |
||
Liens |
=Liens= |
||
* http://www.mongodb.org/ |
* http://www.mongodb.org/ |
||
* https://mms.mongodb.com/ : ''cloud service that makes it easy for you to provision, monitor, backup and scale MongoDB'' |
|||
* https://mongolab.com/ : ''MongoDB-as-a-Service'' |
|||
=Documentation= |
|||
* [http://refcardz.dzone.com/refcardz/mongodb DZone's MongoDB refcard] |
* [http://refcardz.dzone.com/refcardz/mongodb DZone's MongoDB refcard] |
||
* Correspondances avec SQL http://docs.mongodb.org/manual/reference/sql-comparison/ |
* Correspondances avec SQL http://docs.mongodb.org/manual/reference/sql-comparison/ |
||
* Livres https://www.mongodb.org/books |
|||
=Premiers pas avec MongoDB= |
|||
==Exemples de lignes de commande Shell== |
|||
Lancez le serveur |
Lancez le serveur |
||
| Line 31: | Line 36: | ||
</pre> |
</pre> |
||
Quelques commandes d'administration |
==Quelques commandes d'administration== |
||
<pre> |
<pre> |
||
| Line 54: | Line 59: | ||
// db.serverCmdLinesOpts() n'existe plus |
// db.serverCmdLinesOpts() n'existe plus |
||
db.collection.totalIndexSize() |
|||
db.collection.getIndexStats() |
|||
db.shutdownServer() |
db.shutdownServer() |
||
| Line 80: | Line 89: | ||
// show log [name] prints out the last segment of log in memor |
// show log [name] prints out the last segment of log in memor |
||
show log global |
show log global |
||
</pre> |
|||
==Création et requêtes== |
|||
<pre> |
|||
// utiliser une base de données : elle devient la base courante pour les opération suivantes |
|||
use university |
|||
//lister les index de la collection persons |
|||
db.persons.getIndexes() |
|||
// création d'un index sur lastname pour les requêtes de type : la valeur de la clé lastname est unique |
|||
// * db.persons.find( { pseudo: "dd" } ) |
|||
// * db.persons.find().sort( { pseudo: 1 } ) |
|||
db.persons.ensureIndex( { "pseudo": 1 }, { unique: true } ) |
|||
// d'autres options sont disponibles : background, sparse, expireAfterSeconds, dropDups |
|||
use test |
|||
db. |
db.persons.getIndexes() |
||
db. |
db.persons.find() |
||
// ajout d'un objet |
// ajout d'un objet |
||
db. |
db.persons.save( |
||
{ |
{ |
||
pseudo: "dd", |
|||
firstname : "Didier", |
firstname : "Didier", |
||
lastname : "Donsez", |
lastname : "Donsez", |
||
job : "Professor", |
job : "Professor", |
||
skill : [" |
skill : ["Software Engineering","OSGi","IoT"], |
||
hobbies: ["Laser cutter", "DIY"], |
|||
likes : 10 |
|||
} |
} |
||
) |
) |
||
db. |
db.persons.find() |
||
// ajout d'un objet |
// ajout d'un objet |
||
db. |
db.persons.save( |
||
{ |
{ |
||
pseudo: "or", |
|||
firstname : "Olivier", |
firstname : "Olivier", |
||
lastname : "Richard", |
lastname : "Richard", |
||
| Line 107: | Line 136: | ||
skill : ["Network","Grid"], |
skill : ["Network","Grid"], |
||
hobbies: ["3D printing", "DIY"], |
hobbies: ["3D printing", "DIY"], |
||
likes : 20 |
|||
} |
} |
||
) |
) |
||
db. |
db.persons.find() |
||
// ajout d'un objet |
// ajout d'un objet |
||
db. |
db.persons.save( |
||
{ |
{ |
||
pseudo: "np", |
|||
firstname : "Nicolas", |
firstname : "Nicolas", |
||
lastname : "Palix", |
lastname : "Palix", |
||
job : "Professor", |
job : "Professor", |
||
skill : [" |
skill : ["Operating Systems","Phycomp","Network"], |
||
address: "Saint Martin d'Hères", |
address: "Saint Martin d'Hères", |
||
likes : 10 |
|||
} |
} |
||
) |
) |
||
db. |
db.persons.find() |
||
// rechercher 2 objets |
// rechercher 2 objets |
||
db. |
db.persons.find().limit(2) |
||
// rechercher un objet |
// rechercher un objet |
||
db. |
db.persons.findOne() |
||
// rechercher un objet via l'index |
|||
db.persons.find( { pseudo : "dd" } ) |
|||
db.persons.find( { pseudo : "dd" } ).explain() |
|||
// sortie triée sur le nom |
|||
db.persons.find().sort( { pseudo: 1 } ) |
|||
// rechercher les objets dont le champ firstname = "Didier" |
// rechercher les objets dont le champ firstname = "Didier" |
||
db. |
db.persons.find( { firstname : "Didier" } ) |
||
// rechercher les objets dont le champ hobbies n'est pas null |
// rechercher les objets dont le champ hobbies n'est pas null |
||
db. |
db.persons.find( { hobbies : { $ne : null } } ) |
||
// rechercher les objets dont le champ hobbies n'existe pas |
|||
db.persons.find( { hobbies : { $exists: false } } ) |
|||
var p = db.persons.find() |
|||
while ( p.hasNext() ) printjson( p.next().lastname ) |
|||
</pre> |
|||
==Requêtes avancées== |
|||
===Agrégation=== |
|||
<pre> |
|||
// agrégation (type COUNT) par skill : see http://docs.mongodb.org/manual/tutorial/aggregation-with-user-preference-data/ |
|||
db.persons.aggregate( |
|||
[ |
|||
{ $unwind : "$skill" }, |
|||
{ $group : { _id : "$skill" , number : { $sum : 1 } } }, |
|||
{ $sort : { number : -1 } }, |
|||
{ $limit : 5 } |
|||
] |
|||
) |
|||
// agregation (type COUNT) par map-reduce : see http://docs.mongodb.org/manual/tutorial/map-reduce-examples/ |
|||
</pre> |
|||
===Agrégation par [[Map-Reduce]]=== |
|||
<pre> |
|||
var mapFunction1 = function() { |
|||
emit(this.job, this.likes); |
|||
}; |
|||
var reduceFunction1 = function(keyjob, valuesLikes) { |
|||
return Array.sum(valuesLikes); |
|||
}; |
|||
db.persons.mapReduce( |
|||
mapFunction1, |
|||
reduceFunction1, |
|||
{ out: "map_reduce_example1" } |
|||
) |
|||
db.map_reduce_example1.find() |
|||
var mapFunction2 = function() { |
|||
for (var idx = 0; idx < this.skill.length; idx++) { |
|||
var key = this.skill[idx]; |
|||
var value = 1; |
|||
emit(key, value); |
|||
} |
|||
}; |
|||
var reduceFunction2 = function(keySkill, countVals) { |
|||
count= 0; |
|||
for (var idx = 0; idx < countVals.length; idx++) { |
|||
count += countVals[idx]; |
|||
} |
|||
return count; |
|||
}; |
|||
db.persons.mapReduce( mapFunction2, |
|||
reduceFunction2, |
|||
{ |
|||
out: { merge: "map_reduce_example2" }, |
|||
query: { job: "Professor" } |
|||
// finalize function |
|||
} |
|||
) |
|||
db.map_reduce_example2.find() |
|||
</pre> |
|||
===Manipulation de données géographiques [[GeoJSON]]=== |
|||
Commandes [http://docs.mongodb.org/manual/reference/command/geoNear/ geoNear], [http://docs.mongodb.org/manual/reference/command/geoSearch/ geoSearch] |
|||
====Avec 2dsphere==== |
|||
<pre> |
|||
db.places.insert( |
|||
{ |
|||
loc : { type: "Point", coordinates: [ -73.97, 40.77 ] }, |
|||
name: "Central Park", |
|||
category : "Parks" |
|||
} |
|||
) |
|||
db.places.insert( |
|||
{ |
|||
loc : { type: "Point", coordinates: [ -73.88, 40.78 ] }, |
|||
name: "La Guardia Airport", |
|||
category : "Airport" |
|||
} |
|||
) |
|||
db.places.ensureIndex( { loc : "2dsphere" , category : -1, name: 1 } ) |
|||
db.places.find( { loc : |
|||
{ $geoWithin : |
|||
{ $geometry : |
|||
{ type : "Polygon" , |
|||
coordinates : [ [ |
|||
[ 0 , 0 ] , |
|||
[ 3 , 6 ] , |
|||
[ 6 , 1 ] , |
|||
[ 0 , 0 ] |
|||
] ] |
|||
} } } } ) |
|||
db.places.find( { loc : |
|||
{ $geoWithin : |
|||
{ $centerSphere : |
|||
[ [ -88 , 30 ] , 10 / 3959 ] |
|||
} } } ) |
|||
</pre> |
|||
====Avec 2d==== |
|||
<pre> |
|||
db.places.ensureIndex( { loc : "2d" } , |
|||
{ min : -180 , max : +180 , bits : 20} ) |
|||
db.places.find( { loc : |
|||
{ $geoWithin : |
|||
{ $box : [ [ 0 , 0 ] , |
|||
[ 100 , 100 ] ] |
|||
} } } ) |
|||
db.places.find( { loc: { $geoWithin : |
|||
{ $center : [ [-74, 40.74 ] , 10 ] |
|||
} } } ) |
|||
</pre> |
|||
====Avec Haystack Index==== |
|||
A haystack index is a special 2d geospatial index that is optimized to return results over small |
|||
<pre> |
|||
db.places.insert({ poi : 100, pos: { lng : 126.9, lat : 35.2 } , type : "restaurant"}) |
|||
db.places.insert({ poi : 200, pos: { lng : 127.5, lat : 36.1 } , type : "restaurant"}) |
|||
db.places.insert({ poi : 300, pos: { lng : 128.0, lat : 36.7 } , type : "national park"}) |
|||
db.places.ensureIndex( { pos : "geoHaystack", type : 1 } , |
|||
{ bucketSize : 1 } ) |
|||
db.runCommand( { geoSearch : "places" , |
|||
search : { type: "restaurant" } , |
|||
near : [-74, 40.74] , |
|||
maxDistance : 10 } ) |
|||
</pre> |
|||
===Modification et Suppression=== |
|||
<pre> |
|||
db.persons.update( |
|||
{ job: "Professor" } , |
|||
{ $inc: { likes: 1 } }, |
|||
{ multi: true } |
|||
) |
|||
// script de modification des champs "address" |
// script de modification des champs "address" |
||
db. |
db.persons.find( { address: {$ne : null}}).forEach( |
||
function update(e) { |
function update(e) { |
||
var address = e.address; |
var address = e.address; |
||
| Line 146: | Line 354: | ||
e.address.way = address; |
e.address.way = address; |
||
e.address.city = ""; |
e.address.city = ""; |
||
db. |
db.persons.save(e); |
||
} |
} |
||
) |
) |
||
// suppression de persons de la collection |
|||
db.persons.remove( { job: { $exists: false } } ) |
|||
exit |
exit |
||
</pre> |
</pre> |
||
Voir les équivalences avec SQL http://docs.mongodb.org/manual/reference/sql-comparison/ |
|||
<pre> |
<pre> |
||
./bin/mongostat |
./bin/mongostat |
||
</pre> |
</pre> |
||
==Utilisation de l'interface [[RESTFul]]== |
|||
* http://docs.mongodb.org/ecosystem/tools/http-interfaces/ |
|||
http://127.0.0.1:28017/university/persons |
|||
curl -GET http://127.0.0.1:28017/university/persons |
|||
==Utilisation avec [[Node.js]] et [[Mongoose]]== |
|||
Voir [[Mongoose]] |
|||
==Utilisation avec [[Node-RED]]== |
|||
[[Image:Node-RED2.png|300px|right|thumb|Node RED with MQTT, OpenHAB, MongoDB, Redis.io, RabbitMQ, Moquette, Mosquitto ...]] |
|||
Il existe dans [[Node-RED]] un noeud pour sauvegarder les messages (json) transformés par un flow dans une base MongoDB. Le serveur mongod doit être préalablement démarré. |
|||
=Replication= |
|||
http://docs.mongodb.org/manual/replication/ |
|||
=Sharding= |
|||
http://docs.mongodb.org/manual/core/sharding-introduction/ |
|||
Latest revision as of 04:41, 13 November 2014
SBGD NoSQL
- écrit en C++
- tolérance aux pannes par réplication (replicat set)
- passage à l'échelle (horizontal scaling) en distribuant une base de données entre plusieurs processus mongod (sharding, guide)
- shell Javascript (plus ...)
- stockage native des objets JSON
- support de persistance pour les programmes Node.js (plus ... et Mongoose)
Liens
- http://www.mongodb.org/
- https://mms.mongodb.com/ : cloud service that makes it easy for you to provision, monitor, backup and scale MongoDB
- https://mongolab.com/ : MongoDB-as-a-Service
Documentation
- DZone's MongoDB refcard
- Correspondances avec SQL http://docs.mongodb.org/manual/reference/sql-comparison/
- Livres https://www.mongodb.org/books
Premiers pas avec MongoDB
Lancez le serveur
./bin/mongod --rest --dbpath ./data/db
""Remarque"" : en production, ajoutez les options ./bin/mongod --nohttpinterface --bing_ip <address> --auth --logappend ... --dbpath ./data/db
Ouvrez les pages d'administration via le serveur HTTP et l'interface REST
Lancez le shell
./bin/mongo
Quelques commandes d'administration
// Quelques commandes d'administration
help
db.help()
db.version()
db.stats()
db.serverStatus()
db.currentOp()
db.killOp(1234)
prompt=function() { return (new Date())+"$ "; }
db.getLastError()
// db.serverCmdLinesOpts() n'existe plus
db.collection.totalIndexSize()
db.collection.getIndexStats()
db.shutdownServer()
Relancez le serveur mongod
// show dbs show database names show dbs // show collections show collections in current database show collections // show users show users in current database show users // show profile show most recent system.profile entries with time >= 1ms show profile // show logs show the accessible logger names show logs // show log [name] prints out the last segment of log in memor show log global
Création et requêtes
// utiliser une base de données : elle devient la base courante pour les opération suivantes
use university
//lister les index de la collection persons
db.persons.getIndexes()
// création d'un index sur lastname pour les requêtes de type : la valeur de la clé lastname est unique
// * db.persons.find( { pseudo: "dd" } )
// * db.persons.find().sort( { pseudo: 1 } )
db.persons.ensureIndex( { "pseudo": 1 }, { unique: true } )
// d'autres options sont disponibles : background, sparse, expireAfterSeconds, dropDups
db.persons.getIndexes()
db.persons.find()
// ajout d'un objet
db.persons.save(
{
pseudo: "dd",
firstname : "Didier",
lastname : "Donsez",
job : "Professor",
skill : ["Software Engineering","OSGi","IoT"],
hobbies: ["Laser cutter", "DIY"],
likes : 10
}
)
db.persons.find()
// ajout d'un objet
db.persons.save(
{
pseudo: "or",
firstname : "Olivier",
lastname : "Richard",
job : "Professor",
skill : ["Network","Grid"],
hobbies: ["3D printing", "DIY"],
likes : 20
}
)
db.persons.find()
// ajout d'un objet
db.persons.save(
{
pseudo: "np",
firstname : "Nicolas",
lastname : "Palix",
job : "Professor",
skill : ["Operating Systems","Phycomp","Network"],
address: "Saint Martin d'Hères",
likes : 10
}
)
db.persons.find()
// rechercher 2 objets
db.persons.find().limit(2)
// rechercher un objet
db.persons.findOne()
// rechercher un objet via l'index
db.persons.find( { pseudo : "dd" } )
db.persons.find( { pseudo : "dd" } ).explain()
// sortie triée sur le nom
db.persons.find().sort( { pseudo: 1 } )
// rechercher les objets dont le champ firstname = "Didier"
db.persons.find( { firstname : "Didier" } )
// rechercher les objets dont le champ hobbies n'est pas null
db.persons.find( { hobbies : { $ne : null } } )
// rechercher les objets dont le champ hobbies n'existe pas
db.persons.find( { hobbies : { $exists: false } } )
var p = db.persons.find()
while ( p.hasNext() ) printjson( p.next().lastname )
Requêtes avancées
Agrégation
// agrégation (type COUNT) par skill : see http://docs.mongodb.org/manual/tutorial/aggregation-with-user-preference-data/
db.persons.aggregate(
[
{ $unwind : "$skill" },
{ $group : { _id : "$skill" , number : { $sum : 1 } } },
{ $sort : { number : -1 } },
{ $limit : 5 }
]
)
// agregation (type COUNT) par map-reduce : see http://docs.mongodb.org/manual/tutorial/map-reduce-examples/
Agrégation par Map-Reduce
var mapFunction1 = function() {
emit(this.job, this.likes);
};
var reduceFunction1 = function(keyjob, valuesLikes) {
return Array.sum(valuesLikes);
};
db.persons.mapReduce(
mapFunction1,
reduceFunction1,
{ out: "map_reduce_example1" }
)
db.map_reduce_example1.find()
var mapFunction2 = function() {
for (var idx = 0; idx < this.skill.length; idx++) {
var key = this.skill[idx];
var value = 1;
emit(key, value);
}
};
var reduceFunction2 = function(keySkill, countVals) {
count= 0;
for (var idx = 0; idx < countVals.length; idx++) {
count += countVals[idx];
}
return count;
};
db.persons.mapReduce( mapFunction2,
reduceFunction2,
{
out: { merge: "map_reduce_example2" },
query: { job: "Professor" }
// finalize function
}
)
db.map_reduce_example2.find()
Manipulation de données géographiques GeoJSON
Avec 2dsphere
db.places.insert(
{
loc : { type: "Point", coordinates: [ -73.97, 40.77 ] },
name: "Central Park",
category : "Parks"
}
)
db.places.insert(
{
loc : { type: "Point", coordinates: [ -73.88, 40.78 ] },
name: "La Guardia Airport",
category : "Airport"
}
)
db.places.ensureIndex( { loc : "2dsphere" , category : -1, name: 1 } )
db.places.find( { loc :
{ $geoWithin :
{ $geometry :
{ type : "Polygon" ,
coordinates : [ [
[ 0 , 0 ] ,
[ 3 , 6 ] ,
[ 6 , 1 ] ,
[ 0 , 0 ]
] ]
} } } } )
db.places.find( { loc :
{ $geoWithin :
{ $centerSphere :
[ [ -88 , 30 ] , 10 / 3959 ]
} } } )
Avec 2d
db.places.ensureIndex( { loc : "2d" } ,
{ min : -180 , max : +180 , bits : 20} )
db.places.find( { loc :
{ $geoWithin :
{ $box : [ [ 0 , 0 ] ,
[ 100 , 100 ] ]
} } } )
db.places.find( { loc: { $geoWithin :
{ $center : [ [-74, 40.74 ] , 10 ]
} } } )
Avec Haystack Index
A haystack index is a special 2d geospatial index that is optimized to return results over small
db.places.insert({ poi : 100, pos: { lng : 126.9, lat : 35.2 } , type : "restaurant"})
db.places.insert({ poi : 200, pos: { lng : 127.5, lat : 36.1 } , type : "restaurant"})
db.places.insert({ poi : 300, pos: { lng : 128.0, lat : 36.7 } , type : "national park"})
db.places.ensureIndex( { pos : "geoHaystack", type : 1 } ,
{ bucketSize : 1 } )
db.runCommand( { geoSearch : "places" ,
search : { type: "restaurant" } ,
near : [-74, 40.74] ,
maxDistance : 10 } )
Modification et Suppression
db.persons.update(
{ job: "Professor" } ,
{ $inc: { likes: 1 } },
{ multi: true }
)
// script de modification des champs "address"
db.persons.find( { address: {$ne : null}}).forEach(
function update(e) {
var address = e.address;
e.address = new Object();
e.address.way = address;
e.address.city = "";
db.persons.save(e);
}
)
// suppression de persons de la collection
db.persons.remove( { job: { $exists: false } } )
exit
Voir les équivalences avec SQL http://docs.mongodb.org/manual/reference/sql-comparison/
./bin/mongostat
Utilisation de l'interface RESTFul
http://127.0.0.1:28017/university/persons
curl -GET http://127.0.0.1:28017/university/persons
Utilisation avec Node.js et Mongoose
Voir Mongoose
Utilisation avec Node-RED
Il existe dans Node-RED un noeud pour sauvegarder les messages (json) transformés par un flow dans une base MongoDB. Le serveur mongod doit être préalablement démarré.
Replication
http://docs.mongodb.org/manual/replication/