Data Deletion in Sequelize

Think of deleting data like cleaning out a closet - sometimes you need to remove a single item, and other times you need to clear out an entire section. Let's learn how to do both safely and effectively!

Single Record Deletion

Imagine you're managing an inventory system and need to remove discontinued products:


// Basic single record deletion
const deleteProduct = async (productId) => {
    // Find the product
    const product = await Product.findByPk(productId);
    
    if (!product) {
        throw new Error('Product not found');
    }
    
    // Delete the product
    await product.destroy();
    
    return { message: 'Product successfully deleted' };
};

// With soft delete (paranoid)
const softDeleteProduct = async (productId) => {
    const product = await Product.findByPk(productId);
    
    if (!product) {
        throw new Error('Product not found');
    }
    
    await product.destroy({ force: false }); // Soft delete
    return { message: 'Product archived' };
};
                

Multiple Record Deletion

Like clearing out all expired items from inventory:


// Delete multiple records meeting certain criteria
const removeExpiredProducts = async () => {
    const result = await Product.destroy({
        where: {
            expiryDate: {
                [Op.lt]: new Date()
            }
        }
    });
    
    return { deletedCount: result };
};

// Delete with transaction
const bulkDeleteProducts = async (categoryId) => {
    const t = await sequelize.transaction();
    
    try {
        const result = await Product.destroy({
            where: { categoryId },
            transaction: t
        });
        
        await t.commit();
        return { deletedCount: result };
    } catch (error) {
        await t.rollback();
        throw error;
    }
};
                

Real-World Examples

User Account Deletion System


const deleteUserAccount = async (userId) => {
    const t = await sequelize.transaction();
    
    try {
        // Find user with associated data
        const user = await User.findByPk(userId, {
            include: [
                { model: Post },
                { model: Comment },
                { model: Profile }
            ],
            transaction: t
        });
        
        if (!user) {
            throw new Error('User not found');
        }
        
        // Archive important data
        await UserArchive.create({
            userId: user.id,
            userData: JSON.stringify(user.toJSON()),
            archivedAt: new Date()
        }, { transaction: t });
        
        // Delete associated data
        await Promise.all([
            Post.destroy({ where: { userId }, transaction: t }),
            Comment.destroy({ where: { userId }, transaction: t }),
            Profile.destroy({ where: { userId }, transaction: t })
        ]);
        
        // Finally, delete user
        await user.destroy({ transaction: t });
        
        await t.commit();
        return { message: 'Account successfully deleted' };
    } catch (error) {
        await t.rollback();
        throw error;
    }
};
                

E-commerce Order Cleanup System


const cleanupAbandonedOrders = async () => {
    const TWO_HOURS = 2 * 60 * 60 * 1000;
    
    const result = await Order.destroy({
        where: {
            status: 'pending',
            createdAt: {
                [Op.lt]: new Date(Date.now() - TWO_HOURS)
            }
        },
        include: [{
            model: OrderItem,
            required: true
        }]
    });
    
    return { 
        message: `Cleaned up ${result} abandoned orders` 
    };
};
                

Paranoid Delete (Soft Delete)


// Model definition with paranoid option
const Product = sequelize.define('Product', {
    name: DataTypes.STRING,
    price: DataTypes.DECIMAL
}, {
    paranoid: true // Enables soft delete
});

// Implementing soft delete functionality
const softDeleteManager = {
    delete: async (model, id) => {
        const record = await model.findByPk(id);
        if (!record) throw new Error('Record not found');
        
        await record.destroy(); // Performs soft delete
        return { message: 'Record archived' };
    },
    
    restore: async (model, id) => {
        const record = await model.findByPk(id, { 
            paranoid: false // Include soft-deleted records
        });
        if (!record) throw new Error('Record not found');
        
        await record.restore();
        return { message: 'Record restored' };
    },
    
    forceDelete: async (model, id) => {
        const record = await model.findByPk(id, { 
            paranoid: false 
        });
        if (!record) throw new Error('Record not found');
        
        await record.destroy({ force: true });
        return { message: 'Record permanently deleted' };
    }
};
                

Cascade Deletion


// Setting up cascade delete in model associations
module.exports = (sequelize, DataTypes) => {
    const Post = sequelize.define('Post', {
        title: DataTypes.STRING,
        content: DataTypes.TEXT
    });
    
    Post.associate = (models) => {
        Post.hasMany(models.Comment, {
            foreignKey: 'postId',
            onDelete: 'CASCADE'
        });
    };
    
    return Post;
};

// Using cascade delete
const deletePostWithComments = async (postId) => {
    const post = await Post.findByPk(postId);
    if (!post) throw new Error('Post not found');
    
    // This will automatically delete all associated comments
    await post.destroy();
    
    return { message: 'Post and comments deleted' };
};
                

Best Practices

  • Use Transactions: Wrap related deletions in transactions
  • Validate Before Delete: Always check if records exist
  • Consider Soft Delete: Use paranoid option for sensitive data
  • Handle Dependencies: Consider cascade effects
  • Archive Important Data: Keep records of deleted data when necessary

Common Pitfalls to Avoid

  • Not handling cascading deletes properly
  • Forgetting to use transactions
  • Missing WHERE clauses in bulk deletes
  • Not considering data relationships
  • Inadequate error handling

Advanced Topics to Explore

  • Custom deletion hooks
  • Batch deletion strategies
  • Recovery mechanisms
  • Audit trails
  • Performance optimization