Data Updates in Sequelize

Think of updating database records like maintaining a library catalog - sometimes you need to correct a single book's information, and other times you need to update an entire section. Let's explore how to handle both scenarios effectively!

Single Record Updates

Imagine you're correcting information in a personnel file - you can update one piece of information or multiple details at once:

Method 1: Find, Modify, and Save


// Example: Updating an employee's contact information
const updateEmployeeContact = async (employeeId, newContact) => {
    // Find the employee
    const employee = await Employee.findByPk(employeeId);
    
    if (!employee) {
        throw new Error('Employee not found');
    }
    
    // Update contact information
    employee.email = newContact.email;
    employee.phone = newContact.phone;
    
    // Save changes
    await employee.save();
    
    return employee;
};
                

Method 2: Using Set Method


// Example: Updating multiple employee details at once
const updateEmployeeDetails = async (employeeId, updates) => {
    const employee = await Employee.findByPk(employeeId);
    
    if (!employee) {
        throw new Error('Employee not found');
    }
    
    employee.set(updates);
    await employee.save();
    
    return employee;
};
                

Multiple Record Updates

Think of this like updating the prices of all products in a specific category:


// Example: Applying a price increase to all products in a category
const updateCategoryPrices = async (categoryId, increasePercentage) => {
    const result = await Product.update(
        {
            price: sequelize.literal(`price * ${1 + (increasePercentage/100)}`)
        },
        {
            where: { categoryId },
            // Add validation if needed
            validate: true,
            individualHooks: true
        }
    );
    
    return result;
};
                

Real-World Examples

E-commerce Order Status Update


const updateOrderStatus = async (orderId, newStatus, userId) => {
    const t = await sequelize.transaction();
    
    try {
        // Find the order
        const order = await Order.findByPk(orderId, {
            transaction: t
        });
        
        if (!order) {
            throw new Error('Order not found');
        }
        
        // Update status
        order.status = newStatus;
        
        // Add status history
        await OrderStatusHistory.create({
            orderId: orderId,
            status: newStatus,
            updatedBy: userId,
            updatedAt: new Date()
        }, { transaction: t });
        
        await order.save({ transaction: t });
        await t.commit();
        
        return order;
    } catch (error) {
        await t.rollback();
        throw error;
    }
};
                

Bulk Product Update System


const bulkUpdateProducts = async (updates) => {
    const t = await sequelize.transaction();
    
    try {
        const results = [];
        
        for (const update of updates) {
            const product = await Product.findByPk(update.id, {
                transaction: t
            });
            
            if (!product) {
                results.push({
                    id: update.id,
                    status: 'error',
                    message: 'Product not found'
                });
                continue;
            }
            
            try {
                await product.update(update, {
                    transaction: t,
                    validate: true
                });
                
                results.push({
                    id: update.id,
                    status: 'success',
                    data: product
                });
            } catch (error) {
                results.push({
                    id: update.id,
                    status: 'error',
                    message: error.message
                });
            }
        }
        
        await t.commit();
        return results;
    } catch (error) {
        await t.rollback();
        throw error;
    }
};
                

Update with Validation


const safeUpdateRecord = async (model, id, updates) => {
    // Find the record
    const record = await model.findByPk(id);
    
    if (!record) {
        throw new Error('Record not found');
    }
    
    // Create temporary instance with updates
    const tempInstance = model.build({
        ...record.toJSON(),
        ...updates
    });
    
    // Validate before updating
    try {
        await tempInstance.validate();
    } catch (error) {
        throw new Error(`Validation failed: ${error.message}`);
    }
    
    // Perform update if validation passes
    return await record.update(updates);
};
                

Working with Seeders


// Example seeder with updates
module.exports = {
    up: async (queryInterface, Sequelize) => {
        await queryInterface.bulkUpdate(
            'Products',
            {
                price: Sequelize.literal('price * 1.1'),
                updatedAt: new Date()
            },
            {
                category: 'Electronics',
                price: {
                    [Sequelize.Op.lt]: 1000
                }
            }
        );
    },
    
    down: async (queryInterface, Sequelize) => {
        await queryInterface.bulkUpdate(
            'Products',
            {
                price: Sequelize.literal('price / 1.1'),
                updatedAt: new Date()
            },
            {
                category: 'Electronics',
                price: {
                    [Sequelize.Op.lt]: 1100
                }
            }
        );
    }
};
                

Best Practices

  • Use Transactions: Wrap related updates in transactions
  • Validate First: Always validate data before updating
  • Be Specific: Use precise WHERE clauses for bulk updates
  • Keep History: Consider logging important changes
  • Handle Errors: Implement comprehensive error handling

Common Pitfalls to Avoid

  • Forgetting to validate before updates
  • Missing WHERE clauses in bulk updates
  • Not using transactions for related updates
  • Inadequate error handling
  • Not considering concurrent updates

Advanced Topics to Explore

  • Optimistic locking
  • Complex transaction patterns
  • Batch processing strategies
  • Update hooks and triggers
  • Performance optimization