Deleting documents in MongoDB uses collection.deleteOne(filter) to remove at most one matching document and collection.deleteMany(filter) to remove all documents matching a filter. Validating IDs, scoping filters by owner ID, and verifying deletedCount protect your collections from accidental data loss.
deleteOne() and deleteMany() with Ownership FiltersAlways check ObjectId.isValid(id) before constructing new ObjectId(id)—passing a malformed string throws a BSONError exception. Including userId in the delete filter prevents one user from deleting another user's document.
import { MongoClient, ObjectId } from 'mongodb';
async function deleteUserNote(notesCollection, noteId, ownerUserId) {
if (!ObjectId.isValid(noteId)) {
throw new Error('Invalid note ID format');
}
const result = await notesCollection.deleteOne({
_id: new ObjectId(noteId),
userId: ownerUserId,
});
return result.deletedCount === 1;
}
async function purgeExpiredSessions(sessionsCollection) {
const result = await sessionsCollection.deleteMany({
expiresAt: { $lt: new Date() },
});
console.log('Purged expired sessions:', result.deletedCount);
}
For user-facing records like invoices or articles, updating { $set: { deletedAt: new Date() } } preserves history and undo capability. For temporary tokens, verification codes, or session logs, attach a TTL (Time-To-Live) index (createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 })) so MongoDB deletes expired documents automatically in the background without manual deleteMany() cron jobs.
deleteMany({}) with an empty object: An empty filter {} wipes every single document in the collection. Guard batch delete helpers so empty filters are rejected unless explicitly intended.result.acknowledged instead of result.deletedCount: acknowledged: true only means MongoDB ran the command—it stays true even when deletedCount is 0 because nothing matched!remove() or delete() methods: Always use deleteOne(), deleteMany(), or findOneAndDelete() when you need the deleted document returned.findOneAndDelete() instead of deleteOne()?Use findOneAndDelete(filter) when you need the deleted document's fields back atomically—for example, popping the next job from a queue or returning deleted metadata in an API response.
deleteMany({}) delete indexes on the collection?No. deleteMany({}) removes documents while keeping indexes intact, whereas collection.drop() removes both documents and all indexes.
ObjectId crashes on invalid URL params?Validate with ObjectId.isValid(req.params.id) first and return HTTP 400 Bad Request or 404 Not Found cleanly.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.