Soft Deletes and Data Recovery
In this lesson, you will learn how to implement a record-marking system that preserves data instead of permanently deleting it from your database.
The Logic of Soft Deletes
When you issue a standard SQL DELETE command, the data is gone forever—a mistake that is often difficult to reverse. In professional Node.js applications, we prefer Soft Deletes. Instead of physically removing a row, we add a flag, typically named deleted_at, to our database schema.
When a user "deletes" an item, your application simply updates this timestamp to the current time. To the application logic, the record is gone, but the data remains safe in the database should you ever need to restore it.
Implementing the Pattern
To implement this, you adjust your queries to always filter out rows where deleted_at is not null. Most modern ORMs allow you to define this behavior globally.
Imagine a Product model. Here is how that logic looks conceptually:
// A "Delete" operation is now just an update
async function softDeleteProduct(id) {
return await db('products')
.where('id', id)
.update({ deleted_at: new Date() });
}
// Data recovery is equally simple
async function restoreProduct(id) {
return await db('products')
.where('id', id)
.update({ deleted_at: null });
}
Filtering Results
Every time you fetch records, your queries must explicitly ignore "deleted" items:
// Fetching active products only
const activeProducts = await db('products')
.whereNull('deleted_at')
.select('*');
This pattern creates a safety net for your application. If a user accidentally deletes their account or a critical piece of content, you don't need to perform a stressful restore from a cold backup; you simply flip the deleted_at value back to null. It turns a catastrophic data loss event into a simple one-line database update.
Key Takeaway: Soft deletes prioritize data safety by masking records with a timestamp rather than permanently removing them from your storage.