Le dilemme SQL vs NoSQL
Pour Keneya, nous avions besoin de stocker :
Fallait-il choisir PostgreSQL OU MongoDB ?
Notre réponse : Les deux.
PostgreSQL pour les données critiques
Pourquoi PostgreSQL ?
Notre schéma PostgreSQL
sql
-- Utilisateurs
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
phone VARCHAR(20) UNIQUE NOT NULL,
role VARCHAR(20) NOT NULL CHECK (role IN ('patient', 'doctor', 'admin')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Médecins
CREATE TABLE doctors (
id UUID PRIMARY KEY REFERENCES users(id),
specialty VARCHAR(100) NOT NULL,
license_number VARCHAR(50) UNIQUE NOT NULL,
consultation_fee INTEGER NOT NULL,
available BOOLEAN DEFAULT true
);
-- Consultations
CREATE TABLE consultations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
patient_id UUID NOT NULL REFERENCES users(id),
doctor_id UUID NOT NULL REFERENCES doctors(id),
scheduled_at TIMESTAMPTZ NOT NULL,
status VARCHAR(20) NOT NULL,
amount_paid INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_consultations_patient ON consultations(patient_id);
CREATE INDEX idx_consultations_doctor ON consultations(doctor_id);
CREATE INDEX idx_consultations_scheduled ON consultations(scheduled_at);Requêtes complexes simplifiées
sql
-- Top 10 médecins par nombre de consultations
SELECT
u.id,
u.email,
d.specialty,
COUNT(c.id) as total_consultations,
AVG(c.amount_paid) as avg_revenue
FROM users u
JOIN doctors d ON u.id = d.id
LEFT JOIN consultations c ON d.id = c.doctor_id
WHERE c.status = 'completed'
GROUP BY u.id, u.email, d.specialty
ORDER BY total_consultations DESC
LIMIT 10;MongoDB pour les documents flexibles
Pourquoi MongoDB ?
Dossiers médicaux
typescript
// Schema MongoDB
interface MedicalRecord {
_id: ObjectId
patientId: string // Référence à PostgreSQL
consultations: Array<{
consultationId: string
doctorId: string
date: Date
diagnosis: string
symptoms: string[]
prescriptions: Array<{
medication: string
dosage: string
duration: string
instructions: string
}>
examResults: Array<{
type: string
result: any
attachments: string[]
}>
notes: string
}>
allergies: string[]
chronicDiseases: string[]
vaccinations: Array<{
name: string
date: Date
nextDose?: Date
}>
vitalSigns: Array<{
date: Date
weight: number
height: number
bloodPressure: string
heartRate: number
temperature: number
}>
createdAt: Date
updatedAt: Date
}Exemple d'utilisation
typescript
// Ajouter une consultation au dossier médical
await MedicalRecordModel.updateOne(
{ patientId },
{
$push: {
consultations: {
consultationId,
doctorId,
date: new Date(),
diagnosis: 'Grippe saisonnière',
symptoms: ['Fièvre', 'Toux', 'Fatigue'],
prescriptions: [{
medication: 'Paracétamol',
dosage: '1g',
duration: '5 jours',
instructions: '3 fois par jour après les repas'
}],
notes: 'Repos conseillé'
}
},
$set: { updatedAt: new Date() }
}
)
// Récupérer l'historique complet
const record = await MedicalRecordModel.findOne({ patientId })
console.log(record.consultations) // Toutes les consultationsSynchronisation PostgreSQL ↔ MongoDB
typescript
// consultation.service.ts
async completeConsultation(consultationId: string, details: ConsultationDetails) {
// 1. Mettre à jour PostgreSQL
await this.pgRepo.update(consultationId, {
status: 'completed',
completedAt: new Date()
})
// 2. Ajouter au dossier médical MongoDB
await this.mongoMedicalRecord.addConsultation({
consultationId,
...details
})
// Si l'un échoue, rollback
// Transaction distribuée avec Saga pattern
}Quand utiliser quoi ?
PostgreSQL pour :
MongoDB pour :
Performance comparée sur Keneya
| Opération | PostgreSQL | MongoDB |
|-----------|-----------|---------|
| Créer utilisateur | 15ms | 12ms |
| Consultation par ID | 8ms | 5ms |
| Dossier médical complet | 45ms (3 joins) | 12ms (1 doc) |
| Top 100 médecins | 120ms | N/A |
| Recherche full-text | 80ms | 35ms |
Conclusion
PostgreSQL et MongoDB ne sont pas en compétition : ils sont complémentaires.
Pour Keneya, cette approche hybride nous offre :
*Questions sur l'architecture de votre base de données ? [Contactez-nous](/contact).*