Les migrations de bases de données sont des modifications apportées à une base de données. Ces modifications peuvent inclure le changement du schéma d’une table, la mise à jour des données dans un ensemble d’enregistrements, l’insertion de données ou la suppression d’une plage d’enregistrements.

Les migrations de bases de données sont généralement exécutées avant le démarrage d’une application et ne s’exécutent pas avec succès plus d’une fois pour la même base de données. Les outils de migration de bases de données conservent un historique des migrations qui ont été exécutées dans une base de données afin qu’elles puissent être suivies à des fins futures.

Dans cet article, vous apprendrez comment configurer et exécuter des migrations de bases de données dans une application API Node.js minimale. Nous utiliserons ts-migrate-mongoose et un script npm pour créer une migration et insérer des données dans une base de données MongoDB. ts-migrate-mongoose prend en charge l’exécution de scripts de migration à partir de code TypeScript ainsi que de code CommonJS.

ts-migrate-mongoose est un cadre de migration pour les projets Node.js qui utilisent mongoose comme mappage objet-données. Il fournit un modèle pour écrire des scripts de migration. Il offre également une configuration pour exécuter les scripts de manière programmatique et depuis la CLI.

Table des matières

Comment configurer le projet

Pour utiliser ts-migrate-mongoose pour les migrations de base de données, vous devez avoir ce qui suit :

  1. Un projet Node.js avec mongoose installé en tant que dépendance.

  2. Une base de données MongoDB connectée au projet.

  3. MongoDB Compass (Facultatif – pour nous permettre de visualiser les changements dans la base de données).

Un dépôt de démarrage qui peut être cloné depuis ts-migrate-mongoose-starter-repo a été créé pour faciliter les choses. Clonez le dépôt, remplissez les variables d’environnement et lancez l’application en exécutant la commande npm start.

Rendez-vous sur http://localhost:8000 avec un navigateur ou un client API tel que Postman et le serveur renverra un texte « Hello there! » pour montrer que l’application de démarrage fonctionne comme prévu.

Comment configurer ts-migrate-mongoose pour le projet

Pour configurer ts-migrate-mongoose pour le projet, installez ts-migrate-mongoose avec cette commande :

npm install ts-migrate-mongoose

ts-migrate-mongoose permet une configuration avec un fichier JSON, un fichier TypeScript, un fichier .env ou via l’interface en ligne de commande. Il est recommandé d’utiliser un fichier .env car le contenu de la configuration peut contenir un mot de passe de base de données et il n’est pas approprié de l’exposer au public. Les fichiers .env sont généralement cachés via des fichiers .gitignore donc ils sont plus sécurisés à utiliser. Ce projet utilisera un fichier .env pour la configuration de ts-migrate-mongoose.

Le fichier devrait contenir les clés suivantes et leurs valeurs :

  • MIGRATE_MONGO_URI – l’URI de la base de données Mongo. Il est identique à l’URL de la base de données.

  • MIGRATE_MONGO_COLLECTION – le nom de la collection (ou table) dans laquelle les migrations doivent être enregistrées. La valeur par défaut est migrations, c’est ce qui est utilisé dans ce projet. ts-migrate-mongoose enregistre les migrations dans MongoDB.

  • MIGRATE_MIGRATIONS_PATH – le chemin vers le dossier pour stocker et lire les scripts de migration. La valeur par défaut est ./migrations, c’est ce qui est utilisé dans ce projet.

Comment insérer des données utilisateur avec ts-migrate-mongoose

Nous avons pu créer un projet et le connecter avec succès à une base de données Mongo. À ce stade, nous voulons insérer des données utilisateur dans la base de données. Nous devons :

  1. Créer une collection (ou table) users

  2. Utiliser ts-migrate-mongoose pour créer un script de migration pour insérer des données

  3. Utiliser ts-migrate-mongoose pour exécuter la migration afin d’insérer les données utilisateur dans la base de données avant le démarrage de l’application

1. Créez une collection d’utilisateurs en utilisant Mongoose

Le schéma Mongoose peut être utilisé pour créer une collection d’utilisateurs (ou table). Les documents d’utilisateurs (ou enregistrements) auront les champs (ou colonnes) suivants : email, favouriteEmoji et yearOfBirth.

Pour créer un schéma Mongoose pour la collection d’utilisateurs, créez un fichier user.model.js à la racine du projet contenant l’extrait de code suivant:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema(
  {
    email: {
      type: String,
      lowercase: true,
      required: true,
    },
    favouriteEmoji: {
      type: String,
      required: true,
    },
    yearOfBirth: {
      type: Number,
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

module.exports.UserModel = mongoose.model("User", userSchema);

2. Créez un script de migration avec ts-migrate-mongoose

ts-migrate-mongoose fournit des commandes CLI qui peuvent être utilisées pour créer des scripts de migration.

En exécutant npx migrate create <nom-du-script> dans le dossier racine du projet, un script sera créé dans le dossier MIGRATE_MIGRATIONS_PATH (./migrations dans notre cas). <nom-du-script> est le nom que nous voulons donner au fichier du script de migration lors de sa création.

Pour créer un script de migration pour peupler les données utilisateur, exécutez:

npx migrate create seed-users

La commande créera un fichier dans le dossier ./migrations avec un nom sous la forme –<horodatage>-seed-users.ts. Le fichier aura le contenu suivant de l’extrait de code:

// Importez vos modèles ici

export async function up (): Promise<void> {
  // Écrivez la migration ici
}

export async function down (): Promise<void> {
  // Écrivez la migration ici
}

La fonction up est utilisée pour exécuter la migration. La fonction down est utilisée pour annuler ce que la fonction up exécute, si nécessaire. Dans notre cas, nous essayons d’ajouter des utilisateurs à la base de données. La fonction up contiendra le code pour ajouter des utilisateurs à la base de données et la fonction down contiendra le code pour supprimer les utilisateurs créés dans la fonction up.

Si la base de données est inspectée avec MongoDB Compass, la collection de migrations aura un document qui ressemble à ceci :

{
  "_id": ObjectId("6744740465519c3bd9c1a7d1"),
  "name": "seed-users",
  "state": "down",
  "createdAt": 2024-11-25T12:56:36.316+00:00,
  "updatedAt": 2024-11-25T12:56:36.316+00:00,
  "__v": 0
}

Le champ state du document de migration est défini sur down. Après son exécution réussie, il passe à up.

Vous pouvez mettre à jour le code dans ./migrations/<timestamp>-seed-users.ts avec celui dans l’extrait ci-dessous :

require("dotenv").config() // charger les variables d'environnement
const db = require("../db.js")
const { UserModel } = require("../user.model.js");

const seedUsers = [
  { email: "[email protected]", favouriteEmoji: "🏃", yearOfBirth: 1997 },
  { email: "[email protected]", favouriteEmoji: "🍏", yearOfBirth: 1998 },
];

export async function up (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.create(seedUsers);}

export async function down (): Promise<void> {
  await db.connect(process.env.MONGO_URI)
  await UserModel.delete({
    email: {
      $in: seedUsers.map((u) => u.email),
    },
  });
}

3. Exécutez la Migration Avant le Démarrage de l’Application

ts-migrate-mongoose nous fournit des commandes CLI pour exécuter les fonctions up et down des scripts de migration.

Avec npx migrate up <nom-du-script>, nous pouvons exécuter la fonction up d’un script spécifique. Avec npx migrate up, nous pouvons exécuter la fonction up de tous les scripts dans le dossier ./migrations avec un state de down dans la base de données.

Pour exécuter la migration avant le démarrage de l’application, nous utilisons des scripts npm. Les scripts npm avec un préfixe de pre s’exécuteront avant un script sans le préfixe pre. Par exemple, s’il y a un script dev et un script predev, chaque fois que le script dev est exécuté avec npm run dev, le script predev s’exécutera automatiquement avant que le script dev ne soit exécuté.

Nous utiliserons cette fonctionnalité des scripts npm pour placer la commande ts-migrate-mongoose dans un script prestart afin que la migration s’exécute avant le script start.

Met à jour le fichier package.json pour avoir un script prestart qui exécute la commande ts-migrate-mongoose pour exécuter la fonction up des scripts de migration dans le projet.

  "scripts": {
    "prestart": "npx migrate up",
    "start": "node index.js"
  },

Avec cette configuration, lorsque npm run start est exécuté pour démarrer l’application, le script prestart s’exécutera pour exécuter la migration en utilisant ts-migrate-mongoose et pour alimenter la base de données avant le démarrage de l’application.

Vous devriez obtenir quelque chose de similaire à l’extrait ci-dessous après avoir exécuté npm run start:

Synchronizing database with file system migrations...
MongoDB connection successful
up: 1732543529744-seed-users.ts 
All migrations finished successfully

> [email protected] start
> node index.js

MongoDB connection successful                      
Server listening on port 8000

Consultez la branche seed-users du dépôt pour voir l’état actuel de la base de code à ce stade de l’article.

Comment construire un point de terminaison API pour récupérer des données ensemencées

Nous pouvons construire un point de terminaison API pour récupérer les données des utilisateurs ensemencées dans notre base de données. Dans le fichier server.js, mettez à jour le code comme indiqué dans l’extrait ci-dessous:

const { UserModel } = require("./user.model.js")

module.exports = async function (req, res) {
  const users = await UserModel.find({}) // récupérer tous les utilisateurs dans la base de données

  res.writeHead(200, { "Content-Type": "application/json" });
  return res.end(JSON.stringify({ // retourner une représentation JSON des données des utilisateurs récupérées
    users: users.map((u) => ({
      email: u.email,
      favouriteEmoji: u.favouriteEmoji,
      yearOfBirth: u.yearOfBirth,
      createdAt: u.createdAt
    }))
  }, null, 2));
};

Si nous lançons l’application et visitons http://localhost:8000 en utilisant Postman ou un navigateur, nous obtenons une réponse JSON similaire à celle ci-dessous :

{
  "users": [
    {
      "email": "[email protected]",
      "favouriteEmoji": "🏃",
      "yearOfBirth": 1997,
      "createdAt": "2024-11-25T14:18:55.416Z"
    },
    {
      "email": "[email protected]",
      "favouriteEmoji": "🍏",
      "yearOfBirth": 1998,
      "createdAt": "2024-11-25T14:18:55.416Z"
    }
  ]
}

Remarquez que si l’application est relancée, le script de migration ne s’exécute plus car l’état de la migration sera désormais up après son exécution réussie.

Consultez la branche fetch-users du dépôt pour voir l’état actuel de la base de code à ce stade de l’article.

Conclusion

Les migrations sont utiles lors de la construction d’applications et qu’il est nécessaire de semer des données initiales pour les tests, semer des utilisateurs administratifs, mettre à jour le schéma de la base de données en ajoutant ou supprimant des colonnes et en mettant à jour les valeurs des colonnes dans de nombreux enregistrements à la fois.

ts-migrate-mongoose peut aider à fournir un cadre pour exécuter des migrations pour vos applications Node.js si vous utilisez Mongoose avec MongoDB.