Apprendre Node.js : MongoDB pour Node.js

Comprendre le paradigme de MongoDB axé sur les documents dans Node.js

Ce tutoriel, proposé par IBM, va vous apprendre à développer une application Node.js en exploitant une base de données MongoDB.

Un espace de discussion vous est proposé sur le forum. N’hésitez pas à apporter vos avis. Commentez Donner une note  l'article (5)

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Dans ce tutoriel, nous allons modifier une application, précédemment connectée à SQLite 3, pour qu'elle utilise MongoDB, l'une des bases de données NoSQL les plus populaires pour les applications Node.js.

NoSQL fait référence à un type de base de données constituant une alternative à la base de données relationnelle. Les trois types de bases de données NoSQL sont les suivants :

MongoDB est une base de données orientée document qui utilise un format JSON binaire (appelé BSON) pour le stockage des données. Comme d'autres bases de données NoSQL, MongoDB a été popularisé par la demande de données volumineuses.

Dans ce tutoriel, vous allez configurer MongoDB en tant que base de données pour l’application « Liste de shopping », puis effectuer une série d’opérations de base de données courantes à l’aide de MongoDB. Vous verrez comment ces opérations se comparent entre SQLite 3 et MongoDB. Vous aurez également une brève introduction à Mongoose, un paquet de Node souvent utilisé en association avec MongoDB.

À la fin de ce tutoriel, vous serez prêt à utiliser l’exemple d’application comme tremplin pour en savoir plus sur MongoDB et Mongoose.

Ce tutoriel fait partie d’un parcours de formation Node.js , proposé par IBM.

Le code que vous devez suivre ainsi que les exemples de ce parcours de formation se trouvent dans mon repo GitHub .

II. À propos de ce tutoriel

Pour cette unité, j'ai converti une application « Liste de shopping » précédemment développée et utilisant une base de données SQLite 3, pour utiliser MongoDB. Le code se trouve sur le repo GitHub du cours .

Je vous recommande de lire d'abord le contenu, en tirant les exemples de code dans votre éditeur. Une fois que vous avez un aperçu, vous serez prêt à configurer MongoDB. Si vous prévoyez d’utiliser MongoDB localement (comme dans le cas de ce tutoriel), vous devrez peut-être l’installer. Si vous avez déjà une installation MongoDB distante, modifiez simplement la propriété appSettings.mongodb_url dans ./config/app-settings.js pour qu'elle pointe vers votre serveur distant.

Ensuite, lancez l’application à partir d’une fenêtre de terminal ou d’une invite de commande :

  1. Ouvrez une fenêtre de terminal et accédez au répertoire Unit-12 dans le référentiel GitHub du cours.
  2. Exécutez npm install pour installer les packages nécessaires à partir du registrenpm.
  3. Si vous exécutez MongoDB localement, démarrez le démon MongoDB : npm run start-mongod dans sa propre fenêtre de terminal dédiée.
  4. Ouvrez une deuxième fenêtre de terminal, accédez au répertoire Unit-12, puis chargez les données dans MongoDB : npm run load-db (le temps de chargement peut prendre plusieurs minutes avant de s’exécuter).
  5. Démarrez l'application : npm start.
  6. Dirigez votre navigateur sur http://localhost: 3000 et jouez avec l'application.

Vous pouvez maintenant commencer à travailler sur le matériel de l'unité, en utilisant le code source et en exécutant l'application comme référence. Pendant que vous jouez avec l'application, voyez si vous pouvez faire correspondre les écrans de l'interface utilisateur avec les modules, les pages et les autres artefacts source utilisés, afin que vous puissiez apprendre comment ils fonctionnent.

III. Documentation de MongoDB pour Node

Au début, la documentation de MongoDB peut être déroutante pour les utilisateurs de Node.js. Les documents de référence d'API pour toute fonction API particulière sont axés sur la manière dont cette fonction API est utilisée dans le shell MongoDB, et non sur la façon dont vous allez l'utiliser dans vos applications nodales.

Lisez la documentation MongoDB pour connaître les concepts généraux, mais consultez la documentation du pilote de Node pour MongoDB pour obtenir des informations spécifiques à l'API.

Notez également que presque chaque fonction API prend un argument qui vous permet de spécifier un rappel lorsque la méthode asynchrone se termine ou si la fonction renvoie une promise. Si vous lisez ce que vous pensez être la documentation de l'API Node et qu'il n'est fait aucune mention d’une fonction de rappel ou d’un retour de promise, vous ne lisez pas la bonne documentation !

C’est particulièrement vrai lorsque vous effectuez une recherche sur le Web : bon nombre des « solutions » que vous trouverez sont destinées au shell MongoDB, mais ne fonctionnent pas dans votre code Node.js. Vous devrez ajouter le rappel ou un then () (pour gérer le retour de promise) afin que ces solutions fonctionnent dans Node.js.

IV. Configurer MongoDB

Pour ce tutoriel, je recommande l’utilisation d’une installation locale non sécurisée, car c’est un moyen simple et facile de se mouiller les pieds dans MongoDB.

Il existe plusieurs façons d’installer MongoDB sur votre ordinateur. Allez à la page des téléchargements de la communauté MongoDB et un écran ressemblant à celui de la figure 1 apparaît.

Image non disponible
Figure 1 : Page de téléchargements de la communauté MongoDB

Sélectionnez l'onglet correspondant à votre plate-forme et suivez les instructions appropriées ci-dessous.

MacOS

Pour MacOS, vous avez deux choix :

  • utiliser une archive (appelée quelque chose comme mongodb-osx-ssl-x86_64-4.0.1.tgz) ;
  • utiliser Homebrew (recommandé).

Si vous choisissez la route tarball, cliquez sur le bouton « Télécharger (tgz) » pour lancer le téléchargement.

Si vous choisissez d'utiliser Homebrew (ce que je recommande), accédez à une fenêtre de terminal et entrez brew install mongodb, puis installez-vous et regardez l'installation. Si vous devez installer Homebrew, cliquez ici pour obtenir des instructions d'installation.

Vous devrez effectuer quelques étapes supplémentaires pour que votre installation MongoDB soit correctement configurée. Consultez le tutoriel d'installation de MongoDB MacOS pour ces instructions.

Windows

Sélectionnez l'onglet Windows et cliquez sur le bouton « Télécharger (msi) » pour lancer le téléchargement.

Vous devrez effectuer quelques étapes supplémentaires pour que votre installation de MongoDB soit correctement configurée. Voir le tutoriel d'installation de MongoDB sur Windows pour ces instructions.

Linux

Sélectionnez l'onglet Linux, puis cliquez sur le bouton « Télécharger (tgz) » pour lancer le téléchargement.

Vous devrez effectuer quelques étapes supplémentaires pour que votre installation de MongoDB soit correctement configurée. Voir le tutoriel d'installation de MongoDB Linux pour ces instructions.

V. L’application « Liste de shopping »

L’application exemple « Liste de shopping » va être modifiée pour utiliser MongoDB et nous allons procéder à ces modifications ensemble. L’implémentation est assez simple et vous constaterez la plupart des modifications apportées aux implémentations DAO (Data Access Object) de l’application :

  • lists-dao-mongodb.js est l'implémentation DAO spécifique à MongoDB pour la collection de listes ;
  • items-dao-mongodb.js est l'implémentation DAO spécifique à MongoDB pour la collection d'éléments.

Dans les sections suivantes, nous examinerons ce qui a changé dans ces deux modules. Avant de le faire, prenons une minute pour réfléchir au passage d’un paradigme relationnel à un paradigme axé sur les documents.

V-A. Notion de tables en SQL versus notion de collections en NoSQL

L'unité atomique de persistance lors de l'utilisation d'une base de données SQL est la ligne. Dans MongoDB, une base de données orientée document, ce concept correspond à un document. La plupart des développeurs ont l'habitude de considérer les atomes de persistance dans nos applications comme des enregistrements. Par conséquent, le mappage d'une ligne sur un document n'est pas vraiment compliqué.

Les choses peuvent devenir plus risquées quand il s'agit de tables. Dans une base de données SQL, les enregistrements sont stockés sous forme de lignes de données dans des tables et les tables sont liées les unes aux autres. Dans un système de stockage orienté document tel que MongoDB, ces enregistrements deviennent des documents dans une collection. Bien qu'elles puissent être en relation, les collections sont plus indépendantes que les tables et contiennent souvent des documents incorporés.

La dénomination est probablement l’un des premiers changements que vous remarquerez dans l’application « Liste de shopping » :

  • la table « item » devient la collection « items » ;
  • la table « brand » (marque) devient la collection « brands » ;
  • la table « shopping_list » devient la collection « shoppingLists ».

Notez également que nous n'avons plus besoin d'une table de jointure entre une shopping_list et ses items. Chaque document shoppingLists de MongoDB contient un tableau des items de la liste de shopping et de leurs identifiants (les références renvoient à l’objet ObjectID des items, bien sûr, pas à des copies desitems).

C’est la vue d’ensemble. Regardons maintenant quelques codes.

V-B. Connexion à MongoDB

Le daemon MongoDB (appelé mongod) doit être en cours d'exécution pour que vous puissiez vous y connecter.

Une fois que MongoDB est en marche, il est assez simple de se connecter. Tout d'abord, vous appelez mongodb.MongoClient.connect () en transmettant l'URL à l'instance MongoDB. L'appel est asynchrone. Si l'appel de fonction aboutit, vous recevez une référence à MongoClient, que vous pouvez utiliser pour extraire une référence à la base de données que vous souhaitez utiliser. Comme la plupart des systèmes de gestion de base de données, MongoDB prend en charge plusieurs bases de données s'exécutant simultanément.

Le code pour se connecter à MongoDB est presque passe-partout, je l’ai donc écrit une fois dans ./utils/utils.js. Tout objet d'accès aux données (DAO) ayant besoin de ce code appelle une méthode qui renvoie une promise. Une fois résolue, cette promise renverra une référence à la base de données.

Le Listing 1 montre la fonction dbConnect() utilisée pour se connecter à MongoDB.

Listing 1. dbConnect() depuis ./utils/utils.js
Sélectionnez
const mongodb = require('mongodb');
.
.
let mongodbClient;
let db;
.
.
function dbConnect() {
    return new Promise((resolve, reject) => {
        if (db) {
            resolve(db);
        } else {
            mongodb.MongoClient.connect(appSettings.mongodb_url, function(err, client) {
                if (err) {
                    logger.error('Erreur de connexion à l’URL de MongoDB URL: ' + appSettings.mongodb_url);
                    reject(err);
                }
                mongodbClient = client;
                db = mongodbClient.db(appSettings.mongodb_db_name);
                // Soyez sûr que la connection est fermée à la sortie de Node
                process.on('exit', (code) => {
                    dbClose();
                })
                resolve(db);
            });
        }
    });
}

Une fois la connexion établie, la promise retournée à l'appelant sera résolue avec une référence à la base de données.

Notez également que :

  • la fonction dbConnect () stocke une référence à l'objet MongoClient afin qu'elle puisse être utilisée ultérieurement pour fermer toute connexion à une base de données ouverte ;
  • un gestionnaire process.on ('exit') est installé pour fermer la connexion MongoDB lorsque le processus de Node.js est fermé.


Pour fermer la connexion à la base de données, appelez utils.dbClose () , comme indiqué dans le Listing 2.

Listing 2.dbClose() depuis ./utils/utils.js
Sélectionnez
function dbClose() {
    if (mongodbClient && mongodbClient.isConnected()) {
        mongodbClient.close();
    }
}

Les deux implémentations de MongoDB DAO utilisent une expression de fonction immédiatement invocable (IIFE :Immediately Invokable Function Expression). Ces fonctions initialisent une connexion à MongoDB lorsqu’elles sont chargées, évitant ainsi le temps de latence des connexions et des déconnexions pour chaque requête (voir : recommandation MongoDB).

Dans le Listing 3, un IIFE est utilisé pour se connecter à MongoDB dès que le module est chargé.

Listing 3. un IIFE depuis lists-dao-mongodb.js
Sélectionnez
// La référence MongoDB
let db;

// Obtenez une connexion DB quand le module est chargé
(function getDbConnection() {
    utils.dbConnect().then((database) => {
        db = database;
    }).catch((err) => {
        logger.error('Erreur pendant l’initialisation de la BD : ' + err.message, 'lists-dao-mongogb.getDbConnection()');
    });
})();

La référence de base de données est stockée pour une utilisation facile par d'autres méthodes dans lists-dao-mongodb.

V-C. Requête sur les collections MongoDB

Dans MongoDB, les enregistrements sont appelés documents. Les documents sont stockés dans des collections similaires aux tables SQL.

Il existe plusieurs façons de sélectionner des données dans une collection.

La première, et la plus simple, consiste à sélectionner simplement tous les documents de la collection. Pour ce faire, vous obtenez une référence à la collection que vous souhaitez sélectionner, puis utilisez la fonction find() avec un objet de requête vide, qui indique à MongoDB ce qu'il faut sélectionner.

Le Listing 4 montre la fonction fetchAll() du module lists-dao-mongodb.

Listing 4. La fonction fetchAll() sélectionne tous les documents de la liste d’achats de la base de données.
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
function fetchAll() {
     return new Promise((resolve, reject) => {
         let lists = db.collection('shoppingLists');
         lists.find({}).toArray((err, documents) => {
             if (err) {
                 logger.error('Erreur survenue: ' + err.message, 'fetchAll()');
                 reject(err);
             } else {
                 logger.debug('Raw data: ' + JSON.stringify(documents), 'fetchAll()');
                 resolve({ data: JSON.stringify(documents), statusCode: (documents.length > 0) ? 200 : 404 });
             }
         });
     });
 }

Notez que vous obtenez d'abord une référence à la collection shoppingLists (ligne 3), puis appelez la fonction find() sur cette référence (ligne 4).

Le paramètre de requête transmis à find() est un objet JSON vide ({}), qui indique à MongoDB de « tout sélectionner » (ou, si vous préférez, de ne « rien filtrer »). MongoDB renvoie un curseur. L'appel de toArray() sur le curseur le convertit en tableau. Si cela réussit, la référence aux documents résultants (le deuxième argument du rappel de la ligne 4) contient un objet JSON de toutes les listes de courses de la base de données.

Les documents JSON sont « stringifiés » (à l'aide de stringify()) et renvoyés à l'appelant, ainsi qu'un code d'état reflétant les résultats de la requête.

En savoir plus sur le curseur :

Le curseur de MongoDB a une interface fluide et constitue un objet extrêmement polyvalent que vous pouvez utiliser pour transformer les résultats des opérations MongoDB. Assurez-vous de consulter la documentation du pilote Node de MongoDB pour en savoir plus sur l'objet Cursor.

V-C-1. La fonction de find() de MongoDB dans une requête

La sélection de tous les documents est assez facile, mais que se passe-t-il si vous souhaitez appliquer une sorte de filtre ? Supposons que vous recherchiez tous les éléments dont la propriété itemDescription contient un ensemble de mots spécifique.

Le Listing 5 montre comment effectuer une nouvelle recherche à l'aide de la fonction find(), mais cette fois avec une requête.

Listing 5. La fonction findByDescription() du module items-dao-mongodb
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
function findByDescription(partialDescription) {
     return new Promise((resolve, reject) => {
         let items = db.collection('items');
         let search = `.*${partialDescription}.*`;
         items.find({ itemDescription: { $regex: search, $options: 'i' } }).toArray((err, documents) => {
             if (err) {
                 reject(err);
             } else {
                 resolve({ data: JSON.stringify(documents), statusCode: (documents.length > 0) ? 200 : 404 });
             }
         });
     });
 }

Dans cet exemple, vous obtenez d'abord une référence à la collection (ligne 3), puis appelez la fonction find() (ligne 5) en passant la requête, qui ressemble à ceci :

{ itemDescription: { $regex: search, $options: 'i' } }

La requête est un objet JSON qui dit: « Faites une correspondance d'expression régulière insensible à la casse de la propriété itemDescription avec la chaîne de recherche .* ${partialDescription}.* ».

En supposant qu’il n’y ait pas d’erreur, le curseur contenant les documents correspondant à la requête sera converti en tableau. L'objet JSON sous forme de chaîne sera ensuite renvoyé à l'appelant.

V-C-2. La fonction findOne()

Si vous voulez un seul document à partir d’une requête, vous pouvez utiliser la fonction findOne() de MongoDB, comme indiqué dans le Listing 6.

Listing 6. La fonction findById() dans le module items-dao-mongodb
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
function findById(id) {
    return new Promise((resolve, reject) => {
        let items = db.collection('items');
        items.findOne({ _id: new mongodb.ObjectID(id) }).then((document) => {
            if (document) {
                resolve({ data: JSON.stringify(document), statusCode: 200});
            } else {
                let message = 'No document matching id: ' + id + ' could be found!';
                logger.error(message, 'findById()');
                reject(message);
            }
        }).catch((err) => {
            logger.error('Error occurred: ' + err.message, 'findById()');
            reject(err);
        });
    });
}

La fonction findOne() utilisée dans le Listing 6 renvoie une promesse. Une fois résolue, la promesse renvoie zéro ou un document correspondant. Dans ce cas, si aucune correspondance n'est trouvée, la promesse renvoyée par findById() est rejetée. Si l'appel aboutit et que le document est localisé, il est structuré et renvoyé à l'appelant, avec le code d'état HTTP 200.

V-D. Création et mise à jour dans MongoDB

L'application « Liste de shopping » fournit des fonctions permettant de créer et de mettre à jour des listes d'achat et des éléments de liste d'achat. Notre conversion en MongoDB doit donc fournir toutes ces fonctionnalités. Dans les sections suivantes, vous verrez comment MongoDB effectue les opérations de base de données clés dans l’application « Liste de shopping ».

V-D-1. Créer un nouvel élément de collection

L'application « Liste de shopping » permet de créer de nouvelles listes de courses. Dans MongoDB, cette fonctionnalité est fournie par la fonction create() du module lists-dao-mongodb.

Dans le Listing 7, create() est utilisé pour créer un nouvel élément dans la collection shoppingLists.

Listing 7. La fonction create() dans le module lists-dao-mongodb
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
function create(description) {
     return new Promise((resolve, reject) => {
         let lists = db.collection('shoppingLists');
         let listId = mongodb.ObjectId();
         let whenCreated = Date.now();
         let item = {
             _id: listId,
             id: listId,
             description: description,
             whenCreated: whenCreated,
             whenUpdated: null
         };
         lists.insertOne(item, (err, result) => {
             if (err) {
                 logger.error('Error occurred: ' + err.message, 'create()');
                 reject(err);
             } else {
                 resolve({ data: { createdId: result.insertedId }, statusCode: 201 });
             }
         });
     });
 }

Après avoir obtenu une référence à la collection shoppingLists (ligne 3) et créé un nouvel objet ObjectId MongoDB (ligne 4), l'objet JSON représentant le nouveau document shopping list est créé (lignes 6 à 12). Ensuite, la fonction insertOne() est appelée sur la collection pour insérer un seul enregistrement (ligne 13). S'il réussit, la promise est résolue et les données sont renvoyées à l'appelant (ligne 18).

V-D-2. $Lookup de MongoDB (comme une jointure)

Vous aurez parfois besoin de référencer une collection d'une autre.

Avec SQLite3, l'application « Liste de shopping » utilise une table shopping_list_item pour faciliter la relation entre shopping_list et item.

Dans l'application modifiée présentée ici, un document de la collection shoppingLists contient les items qui lui appartiennent dans un tableau.

Vous trouverez ci-dessous un document de liste de shopping brute contenant deux items (dans le tableau items contenant les ObjectIds des items contenus) :

 
Sélectionnez
{
  "_id": "5b69be197f7eac7bb476b41d",
  "id": "5b69be197f7eac7bb476b41d",
  "description": "My Shopping List",
  "whenCreated": 1533656601372,
  "whenUpdated": null,
  "items": [
    "5b68c8201131e61640f07f5a",
    "5b68c8291131e61640f0831f"
  ]
}

Définition de la propriété _id

Si vous vous interrogez sur _id et id : si vous ne fournissez pas une propriété _id sur un document à insérer, MongoDB en créera une pour vous. Pour assurer la compatibilité ascendante, j'ai fourni une propriété id qui doit avoir la même valeur que _id. Dans ce cas, je ne peux pas laisser MongoDB générer automatiquement l’ID.

Afin de joindre ce document à la collection d'éléments dans laquelle les éléments sont stockés, MongoDB fournit une fonction de collection appelée aggregate(). Cette fonction vous permet de créer une aggregation pipeline pour le traitement des données par étapes. à chaque étape, le document est transformé.

L'application « Liste de shopping » utilise la fonction findByIdWithAllItems() pour effectuer cet assemblage, en résolvant les ObjectIds du document shopping list pour extraire les données détaillées des items référencés.

Listing 8. La fonction findByIdWithAllItems()
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
function findByIdWithAllItems(id) {
    return new Promise((resolve, reject) => {
        let lists = db.collection('shoppingLists');
        lists.aggregate([
            { $unwind: '$items' },
            { $match: { _id: new mongodb.ObjectID(id) } },
            { $lookup: { from: 'items', localField: 'items', foreignField: '_id', as: 'items'} }
        ], (err, cursor) => {
            if (err) {
                logger.error('Error occurred: ' + err.message, 'findById()');
                reject(err);
            } else {
                cursor.toArray((err, results) => {
                    if (err) {
                        reject(err);
                    } else {
                        logger.debug('Raw response: ' + JSON.stringify(results), 'findByIdWithAllItems()');
                        resolve({ data: JSON.stringify(results), statusCode: (results) ? 200 : 404  });
                    }
                });
            }
        });
    });
}

L'appel à aggregate() (ligne 4) prend deux paramètres :

  • un tableau des étapes duaggregation pipeline(lignes 5 à 7) ;
  • une fonction de rappel (ligne 8) à laquelle est transmis un curseur que vous pouvez utiliser pour traiter les données.

Les étapes du pipeline sont les suivantes :

  • tout d'abord, l'étape $unwind est utilisée pour associer chaque élément du tableau items aux propriétés du document contenant la liste de shopping à laquelle le tableau appartient (essentiellement, dénormaliser les données) ;
  • ensuite, l'étape $match filtre les documents de la collection shoppingList, en ne conservant que ceux dont l'ObjectId correspond à l'ID transmis à la fonction findByIdWithAllItems() (c'est-à-dire l'ObjectId de la liste de shopping) ;
  • Enfin, l'étape $lookup joint la collection d'éléments (spécifiée par la propriété from) à chaque élément du tableau des items (localField) du champ _id (foreignField).

Après avoir converti le curseur en tableau, le résultat est un tableau déconstruit qui ressemble à ceci :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
[
  {
    "_id": "5b69be197f7eac7bb476b41d",
    "id": "5b69be197f7eac7bb476b41d",
    "description": "My Shopping List",
    "whenCreated": 1533656601372,
    "whenUpdated": null,
    "items": [
      {
        "_id": "5b68c8201131e61640f07f5a",
        "id": "5b68c8201131e61640f07f5a",
        "upc": "084253240499",
        "itemDescription": "Imagine Broth Free Range Chicken Organic",
        "brandId": "5b68c7e01131e61640f04e41"
      }
    ]
  },
  {
    "_id": "5b69be197f7eac7bb476b41d",
    "id": "5b69be197f7eac7bb476b41d",
    "description": "My Shopping List",
    "whenCreated": 1533656601372,
    "whenUpdated": null,
    "items": [
      {
        "_id": "5b68c8291131e61640f0831f",
        "id": "5b68c8291131e61640f0831f",
        "upc": "858328204491",
        "itemDescription": "Wolfgang Puck Organic Free Range Chicken Soup",
        "brandId": "5b68c7e01131e61640f05476"
      }
    ]
  }
]

L'appelant dispose maintenant d'un tableau d'items, chacun avec une description, un upc, etc., prêt à être affiché dans l'interface utilisateur.

V-E. Mise à jour d'un élément de collection

L'application « Liste de shopping » permet de modifier une liste de courses. Le système doit donc permettre de mettre à jour un document de shopping list. La fonction update() de MongoDB dans le module lists-dao-mongodb fait justement cela.

Listing 9. La fonction update() dans le module lists-dao-mongodb
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
function update(id, description) {
    return new Promise((resolve, reject) => {
        let lists = db.collection('shoppingLists');
        lists.updateOne({ _id: new mongodb.ObjectID(id) },
            { $set: { description: description, whenModified: Date.now() } },
            (err, result) => {
                if (err) {
                    logger.error('Error occurred: ' + err.message, 'update()');
                    reject(err);
                } else {
                    resolve({ data: { rowsAffected: result.modifiedCount }, statusCode: 200 });
                }
            }
        );
    });
}

Cette méthode utilise la fonction updateOne() (ligne 4), qui prend trois paramètres :

  1. Un filtre utilisé pour déterminer quel document est mis à jour. Dans ce cas, c’est celui dont le _id correspond au paramètre id à update().
  2. L'opérateur de mise à jour (ligne 5) à appliquer. Dans ce cas, l'opérateur $set qui indique à MongoDB les champs à mettre à jour, comme le fait SET dans une instruction SQL UPDATE.
  3. Une fonction de rappel (ligne 6) pour traiter les résultats.

En cas d'erreur, l'objet err sera enregistré et la promise rejetée.

Si la mise à jour aboutit, il en résulte un objet updateWriteOpResult dont la propriété modifiedCount contient le nombre d'enregistrements mis à jour. (Notez que cet objet est renvoyé en tant qu’attribut rowsAffected pour assurer la compatibilité ascendante avec la couche contrôleur de l’architecture de l’application « Liste de shopping ».)

VI. Opérations supplémentaires

Les modules DAO effectuent un nombre beaucoup plus important d’opérations, que je vous laisse étudier et en apprendre plus par vous-même. Un exemple de ce type est la fonction addItem() dans lists-dao-mongodb.js.

Listing 10. La fonction addItem() dans le module lists-dao-mongodb
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
function addItem(listId, itemId) {
    return new Promise((resolve, reject) => {
        let lists = db.collection('shoppingLists');
        lists.updateOne({ _id: new mongodb.ObjectID(listId) },
            { $push: { items: new mongodb.ObjectID(itemId) }},
            (err, document) => {
                if (err) {
                    logger.error('Error occurred: ' + err.message, 'findById()');
                    reject(err);
                } else {
                    resolve({ data: JSON.stringify(document), statusCode: (document) ? 200 : 404 });
                }
            }
        );
    });
}

Cette fonction utilise l’opérateur du tableau de mise à jour $push pour ajouter le itemId d’un item (son ObjectId)) au tableau des items du document de liste de shopping spécifié par listId.

Je vous encourage à étudier le code source et à vous familiariser avec celui-ci. Le temps que vous consacrerez à l’étude de ces opérations sera du temps bien exploité !

VII. Mongoose

Avant de fermer cette unité, je voudrais vous présenter rapidement Mongoose, un Node package fréquemment utilisé en association avec MongoDB.

Mongoose est une bibliothèque de modélisation de données d'objets (ODM) qui fournit une couche d'abstraction au-dessus de l'API MongoDB principale. En termes simples, Mongoose facilite le travail avec MongoDB en vous permettant de penser en termes d'objets plutôt que de documents.

Si vous avez déjà extrait le répertoire des modèles de l’exemple d’exemple, vous avez peut-être remarqué quelques fichiers qui semblaient hors de propos :

  • brand-schema.js est la définition du schéma Mongoose pour les documents ; brand (marque des articles de shopping) ;
  • item-schema.js est la définition du schéma Mongoose pour les documents item ;
  • items-dao-mongoose.js est l'implémentation DAO spécifique à Mongoose pour l'utilisation de la collection des items.

Les définitions de schéma Mongoose (particulièrement simples comme celles-ci) sont remarquablement lisibles. Considérons la définition du schéma brand :

Listing 11. La définition du schéma brand dans Mongoose
Sélectionnez
const mongoose = require('mongoose');

let Schema = mongoose.Schema;

let brandSchema = new Schema({
    _id: { type: ObjectId, required: true },
    id: { type: ObjectId, required: true },
    description: { type: String, required: true },
    manufacturer: { type: String, required: false },
    address: { type: String, required: false },
    website: { type: String, required: false }
});

module.exports = mongoose.model('Brand', brandSchema);

Et voici le schéma de l’item :

Listing 12. Définition du schéma item dans Mongoose
Sélectionnez
const mongoose = require('mongoose');

let Schema = mongoose.Schema;

let itemSchema = new Schema({
    _id: { type: Schema.ObjectId, required: true },
    id: { type: Schema.ObjectId, required: true },
    itemDescription: { type: String, required: true },
    upc: { type: String, required: true },
    brandId: { type: Schema.ObjectId, ref: 'Brand', required: true }
});

module.exports = mongoose.model('Item', itemSchema);

Consultez la documentation du schéma si vous souhaitez en savoir plus sur les définitions de schéma Mongoose.

J’ai également créé une implémentation DAO spécifique à Mongoose de l’interface item-dao que vous pouvez connecter à l’application avec une ligne de code dans item-dao.js. (Je laisse cela comme un exercice à compléter vous-même, si vous le souhaitez.)

Si vous aimez ce que vous voyez avec Mongoose et souhaitez aller un peu plus loin, vous pouvez vous baser sur les exemples d’items que j’ai fournis, en remplaçant les implémentations DAO par MongoDB natives par des implémentations de Mongoose.

Dans tous les cas, vous devriez absolument visiter Mongoose. Travailler avec MongoDB est beaucoup plus facile.

VIII. Conclusion

Ce tutoriel nous a offert :

  • un bref aperçu de MongoDB ;
  • les instructions pour l'installation de MongoDB localement sur votre plate-forme ;
  • une introduction rapide aux opérations MongoDB dans l'application Shopping List ;
  • une brève introduction à Mongoose, avec des exemples de code pour encourager une exploration plus poussée.

Assurez-vous de vous amuser avec l'application « Liste de shopping » de ce tutoriel unité et regardez la vidéo ci-dessous pour voir davantage l'API MongoDB en action.

J'ai présenté quelques opérations clés avec MongoDB, mais il reste encore beaucoup à apprendre.

IX. Vidéo de démonstration

Dans la vidéo suivante, je vais vous montrer comment utiliser MongoDB et comment j'ai modifié l'application Shopping List pour l'utiliser.


Apprendre Node.js : Connexion d'une application à base de données MongoDB


Remerciements Developpez.com

Developpez.com remercie IBM pour l’autorisation de publication de ce tutoriel. Les remerciements également à Guillaume SIGUI pour la mise au gabarit et f-leb pour la relecture orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2019 J Steven Perry. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.