Le migrazioni del database sono modifiche apportate a un database. Queste modifiche possono includere la modifica dello schema di una tabella, l’aggiornamento dei dati in un insieme di record, l’inserimento di dati o la cancellazione di un intervallo di record.

Le migrazioni del database vengono solitamente eseguite prima che un’applicazione inizi e non vengono eseguite con successo più di una volta per lo stesso database. Gli strumenti di migrazione del database salvano una cronologia delle migrazioni che sono state eseguite in un database in modo che possano essere tracciate per scopi futuri.

In questo articolo, imparerai come impostare ed eseguire migrazioni del database in un’applicazione API Node.js minimale. Utilizzeremo ts-migrate-mongoose e uno script npm per creare una migrazione e inserire dati in un database MongoDB. ts-migrate-mongoose supporta l’esecuzione di script di migrazione dal codice TypeScript così come dal codice CommonJS.

ts-migrate-mongoose è un framework di migrazione per progetti Node.js che utilizzano mongoose come mappatore oggetto-dati. Fornisce un modello per scrivere script di migrazione. Fornisce anche una configurazione per eseguire gli script in modo programmatico e dalla CLI.

Indice

Come configurare il progetto

Per utilizzare ts-migrate-mongoose per le migrazioni del database, è necessario avere quanto segue:

  1. Un progetto Node.js con mongoose installato come dipendenza.

  2. Un database MongoDB collegato al progetto.

  3. MongoDB Compass (Opzionale – per consentirci di visualizzare le modifiche nel database).

È stato creato un repository di base che può essere clonato da ts-migrate-mongoose-starter-repo per facilità. Clonare il repository, compilare le variabili d’ambiente e avviare l’applicazione eseguendo il comando npm start.

Visitare http://localhost:8000 con un browser o un client API come Postman e il server restituirà un testo “Ciao!” per mostrare che l’applicazione di base funziona come previsto.

Come configurare ts-migrate-mongoose per il progetto

Per configurare ts-migrate-mongoose per il progetto, installare ts-migrate-mongoose con questo comando:

npm install ts-migrate-mongoose

ts-migrate-mongoose consente la configurazione con un file JSON, un file TypeScript, un file .env o tramite la CLI. È consigliabile utilizzare un file .env perché il contenuto della configurazione potrebbe contenere una password del database e non è corretto che sia esposta al pubblico. I file .env di solito sono nascosti tramite file .gitignore quindi sono più sicuri da usare. Questo progetto utilizzerà un file .env per la configurazione di ts-migrate-mongoose.

Il file dovrebbe contenere le seguenti chiavi e i loro valori:

  • MIGRATE_MONGO_URI – l’URI del database Mongo. È lo stesso dell’URL del database.

  • MIGRATE_MONGO_COLLECTION – il nome della collezione (o tabella) in cui le migrazioni dovrebbero essere salvate. Il valore predefinito è “migrations” che è quello utilizzato in questo progetto. ts-migrate-mongoose salva le migrazioni su MongoDB.

  • MIGRATE_MIGRATIONS_PATH – il percorso della cartella per memorizzare e leggere gli script di migrazione. Il valore predefinito è ./migrations che è quello utilizzato in questo progetto.

Come inserire i dati dell’utente con ts-migrate-mongoose

Siamo riusciti a creare un progetto e a connetterlo con successo a un database Mongo. A questo punto, vogliamo inserire i dati dell’utente nel database. Dobbiamo:

  1. Creare una collezione (o tabella) di utenti

  2. Usare ts-migrate-mongoose per creare uno script di migrazione per inserire i dati

  3. Usare ts-migrate-mongoose per eseguire la migrazione per inserire i dati dell’utente nel database prima dell’avvio dell’applicazione

1. Crea una raccolta utenti utilizzando Mongoose

Lo schema Mongoose può essere utilizzato per creare una raccolta utenti (o tabella). I documenti utente (o record) avranno i seguenti campi (o colonne): email, favouriteEmoji e yearOfBirth.

Per creare uno schema Mongoose per la raccolta utenti, crea un file user.model.js nella root del progetto contenente il seguente snippet di codice:

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. Crea uno Script di Migrazione con ts-migrate-mongoose

ts-migrate-mongoose fornisce comandi CLI che possono essere utilizzati per creare script di migrazione.

Eseguire npx migrate create <name-of-script> nella cartella root del progetto creerà uno script nella cartella MIGRATE_MIGRATIONS_PATH (./migrations nel nostro caso). <name-of-script> è il nome che vogliamo che il file dello script di migrazione abbia quando viene creato.

Per creare uno script di migrazione per inserire i dati dell’utente, eseguire:

npx migrate create seed-users

Il comando creerà un file nella cartella ./migrations con un nome nel formato –<timestamp>-seed-users.ts. Il file conterrà il seguente contenuto dello snippet di codice:

// Importa i tuoi modelli qui

export async function up (): Promise<void> {
  // Scrivi la migrazione qui
}

export async function down (): Promise<void> {
  // Scrivi la migrazione qui
}

La funzione up viene utilizzata per eseguire la migrazione. La funzione down viene utilizzata per annullare ciò che la funzione up esegue, se necessario. Nel nostro caso, stiamo cercando di inserire utenti nel database. La funzione up conterrà il codice per inserire gli utenti nel database e la funzione down conterrà il codice per eliminare gli utenti creati nella funzione up.

Se il database viene ispezionato con MongoDB Compass, la collezione delle migrazioni avrà un documento che appare così:

{
  "_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
}

Il campo state del documento di migrazione è impostato su down. Dopo che viene eseguito con successo, cambia su up.

Puoi aggiornare il codice in ./migrations/<timestamp>-seed-users.ts con quello nel frammento qui sotto:

require("dotenv").config() // carica le variabili di ambiente
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. Esegui la Migrazione Prima dell’Avvio dell’Applicazione

ts-migrate-mongoose ci fornisce comandi CLI per eseguire le funzioni up e down degli script di migrazione.

Con npx migrate up <nome-dello-script> possiamo eseguire la funzione up di uno script specifico. Con npx migrate up possiamo eseguire la funzione up di tutti gli script nella cartella ./migrations con uno stato down nel database.

Per eseguire la migrazione prima dell’avvio dell’applicazione, facciamo uso degli script npm. Gli script npm con un prefisso di pre verranno eseguiti prima di uno script senza il prefisso pre. Ad esempio, se c’è uno script dev e uno script predev, ogni volta che lo script dev viene eseguito con npm run dev, lo script predev verrà eseguito automaticamente prima che lo script dev venga eseguito.

Sfrutteremo questa funzionalità degli script npm per inserire il comando ts-migrate-mongoose in uno script prestart in modo che la migrazione venga eseguita prima che lo script start venga eseguito.

Aggiorna il file package.json per avere uno script prestart che esegue il comando ts-migrate-mongoose per eseguire la funzione up degli script di migrazione nel progetto.

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

Con questa configurazione, quando viene eseguito npm run start per avviare l’applicazione, lo script prestart verrà eseguito per eseguire la migrazione utilizzando ts-migrate-mongoose e popolare il database prima che l’applicazione venga avviata.

Dovresti avere qualcosa di simile al frammento di codice qui sotto dopo aver eseguito 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

Controlla il ramo seed-users del repository per vedere lo stato attuale della base di codice in questo punto dell’articolo.

Come Costruire un Endpoint API per Recuperare Dati Popolati

Possiamo costruire un endpoint API per recuperare i dati degli utenti popolati nel nostro database. Nel file server.js, aggiorna il codice con quello nel frammento qui sotto:

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

module.exports = async function (req, res) {
  const users = await UserModel.find({}) // recuperare tutti gli utenti nel database

  res.writeHead(200, { "Content-Type": "application/json" });
  return res.end(JSON.stringify({ // restituire una rappresentazione JSON dei dati degli utenti recuperati
    users: users.map((u) => ({
      email: u.email,
      favouriteEmoji: u.favouriteEmoji,
      yearOfBirth: u.yearOfBirth,
      createdAt: u.createdAt
    }))
  }, null, 2));
};

Se avviamo l’applicazione e visitiamo http://localhost:8000 utilizzando Postman o un browser, otteniamo una risposta JSON simile a quella di seguito:

{
  "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"
    }
  ]
}

Nota che se l’applicazione viene eseguita nuovamente, lo script di migrazione non viene eseguito più perché lo stato della migrazione sarà ora up dopo che è stata eseguita con successo.

Controlla il ramo fetch-users del repository per vedere lo stato attuale della codebase in questo punto dell’articolo.

Conclusione

Le migrazioni sono utili durante la costruzione delle applicazioni e c’è bisogno di seminare dati iniziali per i test, seminare utenti amministrativi, aggiornare lo schema del database aggiungendo o rimuovendo colonne e aggiornando i valori delle colonne in molti record contemporaneamente.

ts-migrate-mongoose può aiutare a fornire un framework per eseguire migrazioni per le tue applicazioni Node.js se usi Mongoose con MongoDB.