Définition

Un ORM (Object-Relational Mapping) est une couche entre la base de donnée et les services.

Les ORM permettent de ne pas écrire du SQL. Ces modules fournissent des méthodes pour définir les structures des tables, filtrer, trier, etc.

Cela permet de moins écrire du SQL.


Sequelize

Approches

database-first (base de donnée d’abord)

Dans cette approche, on commence par concevoir la structure de la base de données (tables, colonnes, relations) de manière traditionnelle. Ensuite, Sequelize génère automatiquement des modèles JavaScript qui correspondent à cette structure. C’est idéal lorsque l’on travaille avec une base de données existante ou lorsqu’on préfère un contrôle total sur le schéma de la base.

code-first (Code d’abord)

À l’inverse, le code-first consiste à définir les modèles de données directement dans le code JavaScript, en utilisant Sequelize. Ces modèles sont ensuite utilisés pour créer la structure de la base de données. Cette approche est plus flexible et permet de développer l’application et la base de données en parallèle. Elle est particulièrement adaptée aux nouveaux projets où la structure de la base de données n’est pas encore définie de manière exhaustive.


Installation

Pour l’installer :

npm i -S sequelize

Configuration

Fichier de déclaration de la base de donnée :

const sequelize = new Sequelize('database', 'username', 'password', {
	host: 'localhost',
	dialect: 'mysql' | 'mariadb' | 'sqlite' | 'postgres' | 'mssql',
	pool: {
		max: 5,
		min: 0,
		idle: 10000 // 10s
	}
})

Définir un modèle

const User = sequelize.define('User', {
	username: {
		type: Sequelize.STRING,
		allowNull: false,
		unique: true
	},
	// ...autres champs

On peut alors faire, par exemple:

// Création d'un nouvel utilisateur
const newUser = await User.create({
    username: 'johnDoe',
    email: 'johndoe@example.com',
    // ... autres propriétés
});
console.log('Nouvel utilisateur créé :', newUser.toJSON());
 
// Recherche d'un utilisateur par son ID
const userById = await User.findByPk(newUser.id);
console.log('Utilisateur trouvé par ID :', userById.toJSON());
 
// Mise Ă  jour d'un utilisateur
userById.email = 'newEmail@example.com';
await userById.save();
 
// Suppression d'un utilisateur
await userById.destroy();

Définir des relations

Types de relations

  • HasOne: Un modèle a un seul Ă©lĂ©ment d’un autre modèle. Par exemple, un utilisateur a une seule adresse.
  • BelongsTo: L’inverse de HasOne. Un modèle appartient Ă  un seul Ă©lĂ©ment d’un autre modèle. Par exemple, une adresse appartient Ă  un seul utilisateur.
  • HasMany: Un modèle a plusieurs Ă©lĂ©ments d’un autre modèle. Par exemple, un utilisateur a plusieurs commandes.
  • BelongsToMany: Une relation plusieurs-Ă -plusieurs, nĂ©cessitant une table intermĂ©diaire. Par exemple, un utilisateur peut avoir plusieurs rĂ´les, et un rĂ´le peut ĂŞtre attribuĂ© Ă  plusieurs utilisateurs.

HasOne

Un modèle a une seule instance d’un autre modèle. C’est une relation un-à-un.

// Un utilisateur a une seule adresse
User.hasOne(Address);

BelongsTo

L’inverse de HasOne. Un modèle appartient à une seule instance d’un autre modèle.

// Une adresse appartient Ă  un seul utilisateur
Address.belongsTo(User);

HasMany

Un modèle peut avoir plusieurs instances d’un autre modèle. C’est une relation un-à-plusieurs.

// Un utilisateur peut avoir plusieurs commandes
User.hasMany(Order);

BelongsToMany

Une relation plusieurs-à-plusieurs, nécessitant une table intermédiaire pour gérer les associations.

// Un utilisateur peut avoir plusieurs rôles, et un rôle peut être attribué à plusieurs utilisateurs
User.belongsToMany(Role, { through: 'UserRoles' });
Role.belongsToMany(User, { through: 'UserRoles' });

RequĂŞtes

On peut trouver tous ces opérateurs :

  • findAll(): RĂ©cupère tous les enregistrements d’un modèle.
  • findOne(): RĂ©cupère le premier enregistrement correspondant Ă  un critère.
  • findByPk(): RĂ©cupère un enregistrement par sa clĂ© primaire.
  • create(): CrĂ©e un nouvel enregistrement.
  • update(): Met Ă  jour un enregistrement existant.
  • destroy(): Supprime un enregistrement.

Exemples

Récupérer les utilisateurs qui ont plus de 30 ans

// Trouver tous les utilisateurs dont l'âge est supérieur à 30
const users = await User.findAll({
    where: {
        age: { [Op.gt]: 30 }
    }
});

Récupérer tout les utilisateurs avec leurs commandes

// Récupérer tous les utilisateurs avec leurs commandes
const usersWithOrders = await User.findAll({
    include: [{
        model: Order
    }]
});

Compter le nombre de commandes de chaque utilisateur

// Compter le nombre de commandes par utilisateur
const ordersByUser = await Order.findAll({
    attributes: ['userId', [Sequelize.fn('COUNT', 'id'), 'totalOrders']],
    group: ['userId']
});

Trier les utilisateurs par age descendant

// Trier les utilisateurs par âge décroissant
const usersSorted = await User.findAll({
    order: [['age', 'DESC']]
});

Pour limiter le nombre de résultats et gérer la pagination

// Récupérer les 10 premiers utilisateurs, en commençant à partir du 20ème
const usersPaginated = await User.findAll({
    limit: 10,
    offset: 20
});

Utiliser des requĂŞtes SQL

Il suffit de faire :

const result = await sequelize.query('SELECT * FROM users WHERE age > 30');