Utilisation applicative des systèmes de bases de données NoSQL¶
ODM pour MongoDB¶
-
Qu'est-ce qu'un ODM?
- Object Document Mapper
- Couche d'abstraction entre l'application et la base de données MongoDB
- Permet de modéliser des documents comme des objets JavaScript (classes/schémas)
- Offre : validation, typage, valeurs par défaut, relations, middlewares
- Similaire à un ORM (Object-Relational Mapper) pour les bases de données relationnelles
-
Avec ODM :
- Code structuré avec schémas définis explicitement
- Validation automatique des données avant l'écriture en base
- Méthodes pratiques intégrées :
findById(),create(),save(),populate()… - Gestion simplifiée des relations entre collections
- Sans ODM :
- On travaille directement avec les méthodes de bas niveau du driver officiel MongoDB
- Aucune abstraction des relations
- Plus de code répétitif, plus de risques d'incohérence des données
Mongoose¶
- Mongoose est la bibliothèque ODM la plus populaire pour MongoDB avec Node.js
- Caractéristiques :
- Définition de schémas typés (String, Number, Date, Array, ObjectId…)
- Validation automatique avant l'écriture en base
- Middlewares (hooks) : pre/post save, find, delete…
- Population : résolution de références entre collections
- Méthodes et propriétés virtuelles sur les modèles
- Référence : https://mongoosejs.com
- Installation :
npm install mongoose
Mongoose – Connexion¶
- Connexion à MongoDB avec Mongoose :
import mongoose from 'mongoose';
async function connecter() {
try {
await mongoose.connect('mongodb://localhost:27017/maBaseDeDonnees');
console.log('Connexion réussie');
} catch (err) {
console.error('Erreur :', err);
}
}
// L'URI peut pointer vers MongoDB Atlas (infonuagique) ou un serveur local
Mongoose – Schéma et modèle¶
- Un schéma définit la structure des documents d'une collection.
- Un modèle est une classe JavaScript construite à partir d'un schéma.
import { Schema, model } from 'mongoose';
const produitSchema = new Schema({
nom: { type: String, required: true },
prix: { type: Number, min: 0 },
quantite: { type: Number, default: 0 },
categories: [String],
createdAt:{ type: Date, default: Date.now }
});
// Créer un modèle à partir du schéma :
const Produit = model('Produit', produitSchema);
Mongoose – Création¶
- Création de documents :
// Méthode 1 : Model.create()
const nouveauProduit = await Produit.create({
nom: 'Laptop',
prix: 999.99, quantite: 5,
categories: ['electronique', 'informatique']
});
// Méthode 2 : instanciation + save()
const p = new Produit({ nom: 'Souris', prix: 29.99 });
await p.save();
// Mongoose valide automatiquement les données selon le schéma avant l'insertion
Mongoose – Lecture¶
- Lecture de documents :
// Tous les documents
const produits = await Produit.find();
// Avec filtre (même syntaxe que MongoDB)
const chers = await Produit.find({ prix: { $gt: 500 } });
// Par identifiant MongoDB (_id)
const p = await Produit.findById(id);
// Premier résultat correspondant
const laptop = await Produit.findOne({ nom: 'Laptop' });
// Tri, projection, limite (chaînable)
const top5 = await Produit.find({})
.sort({ prix: -1 }).limit(5).select('nom prix');
Mongoose – Mise à jour et suppression¶
// Mise à jour – retourne le document mis à jour
await Produit.findByIdAndUpdate(id,
{ $set: { prix: 899.99 } },
{ new: true }
);
// Mise à jour de plusieurs documents
await Produit.updateMany({ categorie: 'electronique' }, { $inc: { prix: 10 } });
// Suppression – supprimer un document par _id
await Produit.findByIdAndDelete(id);
// Suppression – supprimer selon un critère
await Produit.deleteMany({ quantite: 0 });
Mongoose – Population (références)¶
- La population (
populate()) permet de résoudre les références entre collections (comme un JOIN en SQL).
// Définition du schéma avec référence :
const commandeSchema = new Schema({
client: { type: Schema.Types.ObjectId, ref: 'Client' },
produits: [{ type: Schema.Types.ObjectId, ref: 'Produit' }]
});
// Requête avec population automatique des références :
const commande = await Commande.findById(id)
.populate('client')
.populate('produits');
// commande.client et commande.produits contiennent les documents complets
OGM pour Neo4j¶
-
Qu'est-ce qu'un OGM?
- Object Graph Mapper
- Couche d'abstraction entre l'application et la base de données de graphes
- Permet de modéliser des nœuds et des relations comme des objets JavaScript
- Offre : schémas de nœuds, validation, gestion des relations, requêtes simplifiées
- Similaire à un ODM, mais pour les graphes (nœuds + relations)
-
Avec OGM :
- Code structuré avec modèles de nœuds définis explicitement
- Validation automatique des propriétés des nœuds
- Méthodes pratiques :
create(),find(),first(),relateTo(),get()… - Gestion déclarative des relations entre modèles
- Sans OGM :
- On exécute directement des requêtes Cypher via le driver officiel Neo4j
- Aucune abstraction des nœuds/relations, pas de validation de schéma
- Plus de code Cypher manuel, plus de risques d'incohérence du graphe
Neode¶
- Neode est un OGM pour Neo4j développé pour Node.js
- Caractéristiques :
- Définition de modèles (nœuds) avec types et contraintes
- Validation automatique des propriétés
- Abstraction des opérations CRUD sur les nœuds
- Gestion déclarative des relations entre modèles
- Possibilité d'exécuter des requêtes Cypher personnalisées si nécessaire
- Référence : https://github.com/adam-cowley/neode
- Installation :
npm install neode
Neode – Connexion¶
- Connexion à Neo4j avec Neode :
import Neode from 'neode';
const instance = new Neode(
'bolt://localhost:7687',
'neo4j', // utilisateur
'motdepasse' // mot de passe
);
// Ou en utilisant des variables d'environnement (.env) :
const instance = new Neode(
process.env.NEO4J_PROTOCOL + '://' + process.env.NEO4J_HOST,
process.env.NEO4J_USERNAME,
process.env.NEO4J_PASSWORD
);
// Le protocole bolt:// est le protocole binaire natif de Neo4j (performances optimales)
Neode – Définir un modèle¶
- Un modèle Neode correspond à un label de nœud dans Neo4j.
instance.model('Personne', {
id: { type: 'uuid', primary: true },
nom: { type: 'string', required: true },
age: { type: 'integer', default: 0 },
actif: { type: 'boolean', default: true },
// Relation déclarée dans le modèle
amis: {
type: 'relationships',
relationship: 'CONNAIT',
target: 'Personne',
direction: 'out'
}
});
Neode – Création et lecture¶
// Création :
const alice = await instance.create('Personne', {
nom: 'Alice', age: 30
});
// alice est un objet Neode Node avec les propriétés du nœud créé
// Lecture – par clé primaire (uuid) :
const noeud = await instance.find('Personne', uuid);
// Premier résultat par propriété :
const p = await instance.first('Personne', 'nom', 'Alice');
// Tous les nœuds d'un modèle :
const tous = await instance.all('Personne');
Neode – Mise à jour et suppression¶
// Mise à jour – propriétés d'un nœud (sur l'objet Neode Node) :
const p = await instance.first('Personne', 'nom', 'Alice');
await p.update({ age: 31 });
// Suppression – supprimer un nœud :
await p.delete();
// Suppression avec toutes ses relations (detach delete) :
await p.detach();
// Requête Cypher personnalisée (si nécessaire) :
const res = await instance.cypher(
'MATCH (p:Personne) WHERE p.age > $min RETURN p',
{ min: 18 }
);
Neode – Relations¶
- Les relations déclarées dans le modèle peuvent être manipulées directement :
// Créer une relation entre deux nœuds :
const alice = await instance.first('Personne', 'nom', 'Alice');
const bob = await instance.first('Personne', 'nom', 'Bob');
// alice -[:CONNAIT]-> bob
await alice.relateTo(bob, 'amis');
// Récupérer les nœuds liés :
const amis = await alice.get('amis');
amis.forEach(a => console.log(a.get('nom')));
// Les propriétés d'un nœud se lisent avec .get('propriete')
Comparaison ODM / OGM¶
| Critère | Mongoose (ODM) | Neode (OGM) |
|---|---|---|
| Base de données | MongoDB (documents) | Neo4j (graphes) |
| Unité de base | Document JSON/BSON | Nœud + Relation |
| Modélisation | Schéma + Modèle | Modèle (label) |
| Langage de requête | Méthodes + MQL | Méthodes + Cypher |
| Relations | Population (ref) | relateTo() / get() |
| Validation | Intégrée au schéma | Intégrée au modèle |
| Hooks / Middleware | Oui (pre/post save…) | Non (natif) |
Dans les deux cas : le pattern ODM/OGM simplifie le code applicatif et améliore la maintenabilité