Deleting precisely, and knowing which operation keeps indexes, avoids nasty data-loss surprises.
deleteOne(filter) removes the first matching document; deleteMany(filter) removes all matches. Both return deletedCount. The filter language is the same as for find, so the safest habit is to run the find first, check what comes back, then switch the method name.
deleteMany({}) removes every document but keeps the collection, its indexes and its validation rules. db.coll.drop() removes the collection itself along with its indexes; it is much faster for emptying huge collections, but you have to recreate indexes afterwards.
findOneAndDelete(filter, { sort }) deletes one document and returns it, which is the classic way to pop a job off a simple queue atomically.
For data that should expire on its own, such as sessions or one-time codes, don't run cleanup jobs. Create a TTL index: createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 }). A background task deletes documents whose date is older than the limit, checking about once a minute, so expiry is not to-the-second.
Many applications prefer soft deletes ($set: { deletedAt: new Date() }) so data can be restored and audited; remember to exclude those documents in queries and maybe use a partial index.
Example
db.sessions.insertMany([
{ user: "ana", createdAt: new Date() },
{ user: "ben", createdAt: new Date("2020-01-01") },
{ user: "cy", createdAt: new Date("2020-01-02") }
])
db.sessions.countDocuments({ createdAt: { $lt: new Date("2021-01-01") } }) // 2: check first
db.sessions.deleteMany({ createdAt: { $lt: new Date("2021-01-01") } })
// { acknowledged: true, deletedCount: 2 }
db.sessions.findOneAndDelete({ user: "ana" }) // returns the removed document
// let the server expire sessions after 1 hour from now on
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
db.sessions.drop() // true: collection and its indexes are goneRemember
- deleteOne / deleteMany take the same filters as find
- deleteMany({}) empties but keeps indexes; drop() removes everything
- TTL indexes expire documents automatically (about every 60 s)
Watch out for
- Running deleteMany with an empty or wrong filter: preview it with find first.