MongoDB: E11000 duplicate key error collection
Solución al error E11000 duplicate key en MongoDB. Cómo manejar índices únicos y evitar conflictos de duplicados en tus colecciones.
¿Por qué ocurre?
MongoDB lanza E11000 cuando intentas insertar o actualizar un documento que viola un índice único (unique index). Las causas más comunes son: - El campo `email` u otro campo único ya existe en la colección - Un índice único compuesto se viola (combinación de campos ya existe) - Datos de prueba duplicados al sembrar (seeding) la base de datos - Race condition: dos requests simultáneos intentan crear el mismo recurso
Solución paso a paso
1. Capturar el error correctamente (Mongoose)
const mongoose = require('mongoose');try {
await User.create({ email: 'test@example.com' });
} catch (error) {
if (error.code === 11000) {
// Extraer el campo duplicado
const field = Object.keys(error.keyValue)[0];
const value = error.keyValue[field];
throw new Error(El ${field} '${value}' ya está registrado);
}
throw error;
}
2. Usar findOneAndUpdate con upsert (upsert seguro)
// En lugar de create(), usar upsert para manejar duplicados
const user = await User.findOneAndUpdate(
{ email: 'test@example.com' }, // filtro
{ $setOnInsert: { name: 'Fran' } }, // solo si es nuevo
{ upsert: true, new: true }
);
3. Verificar antes de insertar
const existing = await User.findOne({ email });
if (existing) {
return res.status(409).json({ error: 'Email ya registrado' });
}
await User.create({ email, name });
4. Ver índices de una colección
// Mongoose
const indexes = await User.collection.getIndexes();
console.log(indexes);// MongoDB Shell
db.users.getIndexes()
5. Eliminar un índice problemático (con cuidado)
// Solo si realmente no necesitas unicidad
await User.collection.dropIndex('email_1');// En el schema, eliminar unique: true
email: { type: String, required: true } // sin unique
6. Middleware Mongoose para manejo global
userSchema.post('save', function(error, doc, next) {
if (error.name === 'MongoServerError' && error.code === 11000) {
next(new Error('Email duplicado'));
} else {
next(error);
}
});
Cómo evitarlo en el futuro
- Siempre captura el código de error `11000` específicamente en operaciones de escritura - Usa `findOneAndUpdate` con `upsert` para operaciones idempotentes - En APIs REST, devuelve HTTP 409 (Conflict) cuando hay duplicados - Usa transacciones MongoDB para operaciones que necesiten consistencia bajo concurrencia - Documenta qué campos tienen índice único en el schema de Mongoose
¿Quieres que una IA te ayude? Genera el prompt perfecto para tu error:
Generador de Prompts