Table des matières
Mongoose
Mongoose est un Object Document Mapper (ODM) utilisé pour MongoDB, en opposition à un Object Relational Mapper (ORM) utilisé dans les bases de données relationnelles.
Installation
L'installation de Mongoose se fait avec npm
:
$ npm install mongoose
On peut utiliser les options -g
ou --save
si nécessaire. Voir la rubrique sur npm
pour plus de détails.
Schema
Simple
Créer un schema est plutôt simple. À la base, il faut spécifier les champs et leur type :
var simpleSchema = new Schema({ fieldName: SchemaType });
Un exemple plus complet ressemblerait à ceci :
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var customerSchema = new Schema({ name: String, address: String, city: String, state: String, country: String, zipCode: Number, createdOn: Date, isActive: Boolean });
Valeurs par défaut
created: { type: Date, default: Date.now }
Types de données
Mongoose Data Type | Javascript Data Type |
---|---|
String | String |
Number | Number |
Date | Object |
Buffer | Object |
Boolean | Boolean |
Mixed | Object |
ObjectId | Object |
Array | Array (Object) |
Schema plus complexe
On peut insérer des schemas à l'intérieur de schemas. Par exemple, un client a une adresse. Le client lui-même est un schema, mais l'adresse peut l'être aussi.
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var addressSchema = new Schema({ type: String, street: String, city: String, state: String, country: String, }); var customerSchema = new Schema({ name: { first: String, last: String }, address: [ addressSchema ], createdOn: { type: Date, default: Date.now }, isActive: { type: Boolean, default: true} });
Il faut remarquer que la propriété address
de customerSchema
est un tableau avec addressSchema
.
Précisions sur les propriétés
Propriété _id
Par défaut, quand on spécifie pas de propriété identité, à l'instance de _id
, cette propriété est ajoutée automatiquement par MongoDB à l'ajout d'un document. La valeur par défaut de cette propriété est un ObjectId. On peut dire à Mongoose, dans le schéma, de ne pas ajouter cette propriété en lui assignant false
.
var noIdSchema = new Schema({ name: String }, { _id: false });
Propriété type
Si on prend l'exemple ci-dessous, on pourrait se demander pourquoi ne pas nommer questionType
tout simplement type
?
var subQuestions = { questionType: String, questionText: String, answers: [ subAnswers ] };
Les schemas de Mongoose ne peuvent pas contenir de propriété type
. Cette propriété a une signification. Celle-ci dit que le document doit être casté au type spécifié. Par exemple, si on change questionType: String
pour type: String
, l'objet sera casté en String et quand ce sera sauvegardé dans MongoDB, on verra type: [object Object]
.
Si on veut une propriété type
, on peut faire type: {type: String}
:
var subQuestions = { type: { type: String }, text: String, answers: [ subAnswers ] };
Ajout de propriétés
Avec add()
utilisé sur un schema, on peut ajouter des propriétés. Ceci est utile par exemple pour avoir des propriété à certaines conditions.
var exempleSchema = new Schema({ name: String }); exempleSchema.add({ address: String });
Modèle
Création
La création d'un modèle se fait avec mongoose.model()
. Le premier argument de model()
est le nom du modèle et le second est le schema. Normalement, le nom du modèle est singulier et sera plurialisé lors de la création de la collection sur MongoDB.
Dans le cas suivant, le nom du modèle est Person
, mais la collection devrait s'appeler People
.
var personSchema = new Schema({ firstName: String, lastName: String }); var Person = mongoose.model('Person', personSchema);
Instanciation
var bob = new Person({ firstName: 'Bob', lastName: 'Doe' });
Sauvegarde
bob.save(callback);
Requêtes
find
La signature de find()
:
Model.find(conditions, fields, options, callback);
Pour retrouver tous les documents d'un modèle, avec aucun callback et une exécution différée :
var allPeople = People.find(); allPeople.exec(function (err, results) { // Gérer l'erreur ou le résultat });
Avec un callback, exécute la requête immédiatement :
Standup.find(function (err, results) { // Gérer l'erreur ou le résultat });
Avec un callback et des conditions :
Standup.find({ memberName: 'David' }, function (err, results) { // Gérer l'erreur ou le résultat });
Limiter les propriétés retournés :
Standup.find({ memberName: 'Mary' }, 'memberName impediment', function (err, results) { });
Exemple d'options :
var query = Standup.findOne({ memberName: 'Bob'}, null, { limit: 10 });
findOne
Signature :
Model.findOne(conditions, [fields], [options], [callback])
Exemple sans callback et sans condition :
var Standup = require('../models/standup.server.model.js'); var query = Standup.findOne(); query.exec(function (err, results) { // gérer le résultat / l'erreur });
Exemple avec un callback :
var query = Standup.findOne({ memberName: 'Mark' });
findById
Signature :
Model.findById(id, [fields], [options], [callback])
var id = '541c6fefefdf9c84172162a6'; var query = Standup.findById(id); query.exec(function (err, doc) { // gérer le résultat / l'erreur });
Même exemple que plus haut, mais avec la méthode chaînée :
Standup.findById(id).exec(function (err, results) { // gérer le résultat / l'erreur });
Exemple pour trouver un document par id
qui retourne tous les propriétés sauf impediment
. Le moins -
devant sert à soustraire des champs.
var query = Standup.findById(id, '-impediment');
Opérateurs de comparaison
Des opérateurs peuvent être utilisés dans les requêtes pour affiner les résultats. Ce sont les mêmes qu'utilisés dans MongoDB.
Les opérateurs de comparaison pour les requêtes | |
---|---|
$gt | greater than |
$gte | greater than or equal to $in exists in |
$lt | less than |
$lte | less than or equal to $ne not equal to |
$nin | does not exist |
Exemple :
Customer.find({discount: {$gte: 10}, function(err, results) { if (err) throw err; console.log(results); });
where
Au lieu d'utiliser une méthode find()
comme celle-ci :
Customer.find({discount: {$gte: 10, $lt: 20}, function(err, results) { // code ... });
On peut utiliser la méthode where()
qui est chaînable :
Customer.where('discount').gte(10).lt(20).exec(function(err, results) { // code ... });
Autre exemple avec plusieurs where()
chaînés :
Customer.where('discount').gte(10).lt(20) .where('zipCode', '12345') .exec(function(err, results) { // code ... });
Mise à jour
Pour mettre à jour un document, on peut le récupérer et le sauvegarder dans le callback :
Standup.findById(id).exec(function (err, doc) { // Mise à jour ... doc.impediment('None'); doc.save(function (err) { // code du callback save. }); });
Le code ci-haut fait en sorte de faire deux requêtes. Il est préférable d'utiliser update()
:
Model.update(conditions, update, [options], [callback])
var condition = { memberName: 'Mary' }; var update = { impediment: 'None – Mary no longer works here!' }; Standup.update(condition, update, function(err, numberAffected, rawResponse) { // code du callback });
Options de l'update
Option | Description | Default Value |
---|---|---|
safe | Safe mode – default to value set in schema | True |
upsert | Create the document if it does not match | False |
multi | Determines if multiple documents should be updated or not | False |
strict | Override the strict option for this update | |
overwrite | Disables the update-only mode to allow for overwrite of document | False |
Exemple qui montre la mise à jour de plusieurs documents qui matchent :
var condition = { firstName: 'Bob' }; var update = { firstName: 'Robert' }; Customer.update(condition, update, { multi: true }, function(err, numberAffected, raw) { // code du callback });
findByIdAndUpdate
Option | Description | Default Value |
---|---|---|
new | Set to true to return the modified document rather than the original. | True |
upsert | Create the document if it does not match | False |
select | Specify the document fields to return |
Suppression
Signature
Model.remove(conditions, [callback])
var condition = { memberName: 'Mary' }; Standup.remove(condition, function(err) { // code callback });
Supprimer tous les documents qui sont créés le ou après le 31 octobre 2014:
var gteDate = new Date(2014, 10, 31); Standup.remove({ createdOn: { $gte: gteDate }}, function (err) { // code callback });
Suppression sans callback :
var query = Standup.remove({ createdOn: { $gte: gteDate }}); query.exec();
findByIdAndRemove
Option | Description | Default Value |
---|---|---|
select | Specify the document fields to return |
Autres exemples de requêtes
var query = Standup.find(); query.sort({ createdOn: 'desc' }) .limit(10) .exec(function(err, results) { // code callback });
Validation
Schema Type | Built-in Validators | ||
---|---|---|---|
String | required | enum | match |
Number | required | min | max |
Date | required | ||
Buffer | required | ||
Boolean | required | ||
Mixed | required | ||
ObjectId | required | ||
Array | required |
Validation required
Exemple de schema :
var customerSchema = new Schema({ name: { type: String, required: true }, address: String, city: String, state: String, country: String, zipCode: Number, createdOn: Date, isActive: Boolean });
Une fois le schema définit, on peut préciser une validation avec required()
. La signature est:
required(required, [message])
customerSchema.path('city').required(true, ‘Oops! Supply a city.’);
Validation match
var reMatch = /[a-zA-Z]/; var customerSchema = new Schema({ name: { type: String, required: true, match: reMatch }, // etc... });
Validation enum
var impediments = ['none', 'minor', 'blocking', 'severe']; var standupSchema = new Schema({ // abbreviated... impediment: { type: String, required: true, enum: impediments } });
Validation min et max
var customerSchema = new Schema({ name: String, discount: { type: Number, min: 5 } }); var customerSchema = new Schema({ name: String, discount: { type: Number, max: 60 } }); var customerSchema = new Schema({ name: String, discount: { type: Number, min: 5, max: 60 } });
Validation personnalisée
Une validation personnalisée peut être spécifiée avec validate
. L'important, c'est que la fonction du validateur retourne true
ou false
, indiquant que la validation est correcte ou non.
var sizeValidator = [ function (val) { return (val.length > 0 && val.length <= 50) }, // Custom error text... 'String must be between 1 and 50 characters long' ]; var personSchema = new Schema({ firstName: { type: String, required: true, validate: sizeValidator }, lastName: { type: String, required: true, validate: sizeValidator }, status: { type: String, required: true, default: 'Alive' } }); var Person = new mongoose.model('Person', personSchema); var newPerson = new Person( { firstName: 'John', lastName: 'Doe' } ); newPerson.save(function (err) { if (err) return handleError(err); // saved the person document! });