When working with databases, we often need to add new records in different ways. Think of it like adding new books to a library - sometimes we want to prepare a book's details before putting it on the shelf (build), and other times we want to place it directly (create). We need to understand three main approaches:
First, using build() and save() separately:
// First approach: Build and Save
const puppy = await Puppy.build({
name: "Trudy",
ageYrs: 2,
weightLbs: 38,
breed: "Brittany Spaniel",
microchipped: false
});
await puppy.save();
Second, using create() to do both steps at once:
// Second approach: Create
const puppy = await Puppy.create({
name: "Beans",
ageYrs: 1.6,
weightLbs: 42,
breed: "Bulldog",
microchipped: true
});
And third, handling data insertion through API endpoints:
// Third approach: API Endpoint
app.post('/puppies/create', async (req, res) => {
const { name, ageYrs, breed, weightLbs, microchipped } = req.body;
const newPuppy = await Puppy.create({
name,
ageYrs,
breed,
weightLbs,
microchipped
});
res.json({
message: "Successfully created new puppy!",
data: newPuppy
});
});
Think of build() and save() like writing a draft before publishing. Here's a complete example with error handling:
// Complete implementation of build and save
const insertPuppyWithBuild = async () => {
try {
// First we build the instance
const puppy = await Puppy.build({
name: "Trudy",
ageYrs: 2,
weightLbs: 38,
breed: "Brittany Spaniel",
microchipped: false
});
// We can make modifications here if needed
if (puppy.weightLbs > 30) {
puppy.size = "large";
}
// Then we save to the database
await puppy.save();
return puppy;
} catch (error) {
console.error("Error inserting puppy:", error);
throw error;
}
};
The create() method is like doing everything in one step. Here's a complete example:
// Complete implementation of create
const insertPuppyWithCreate = async () => {
try {
const puppy = await Puppy.create({
name: "Beans",
ageYrs: 1.6,
weightLbs: 42,
breed: "Bulldog",
microchipped: true
});
return puppy;
} catch (error) {
console.error("Error creating puppy:", error);
throw error;
}
};
When creating API endpoints, we need to handle both the data insertion and the response. Here are complete implementations:
// Build endpoint
app.post('/puppies/build', async (req, res) => {
try {
// Extract data from request body
const { name, ageYrs, breed, weightLbs, microchipped } = req.body;
// Build the puppy instance
const puppy = Puppy.build({
name,
ageYrs,
breed,
weightLbs,
microchipped
});
// Save to database
await puppy.save();
// Send success response
res.json({
message: "Successfully created new puppy using build!",
data: puppy
});
} catch (error) {
// Handle errors appropriately
res.status(500).json({
message: "Error creating puppy",
error: error.message
});
}
});
// Create endpoint
app.post('/puppies/create', async (req, res) => {
try {
// Extract and create in one step
const puppy = await Puppy.create({
name: req.body.name,
ageYrs: req.body.ageYrs,
breed: req.body.breed,
weightLbs: req.body.weightLbs,
microchipped: req.body.microchipped
});
// Send success response
res.json({
message: "Successfully created new puppy!",
data: puppy
});
} catch (error) {
res.status(500).json({
message: "Error creating puppy",
error: error.message
});
}
});
The build() and save() approach is best when you need to:
1. Modify the instance before saving. For example, if you need to calculate some values or make validations:
const puppy = Puppy.build({
name: "Max",
weightLbs: 65
});
// Perform calculations or modifications
puppy.size = puppy.weightLbs > 50 ? "large" : "medium";
// Then save
await puppy.save();
2. Perform custom validation before saving:
const puppy = Puppy.build({
name: "Spot",
ageYrs: 0.5
});
if (puppy.ageYrs < 0.25) {
throw new Error("Puppy is too young");
}
await puppy.save();
The create() method is better when:
1. You have all the data ready and don't need intermediate steps:
// Direct creation when data is ready
await Puppy.create({
name: "Bella",
ageYrs: 1.2,
breed: "Labrador",
weightLbs: 55,
microchipped: true
});
2. You're implementing simple API endpoints where you just need to insert data directly:
app.post('/puppies', async (req, res) => {
const puppy = await Puppy.create(req.body);
res.json(puppy);
});
When inserting data, always implement proper error handling:
// Example of comprehensive error handling
async function insertPuppyWithErrorHandling() {
try {
const puppy = await Puppy.create({
name: "Rex",
ageYrs: 1.5,
breed: "German Shepherd",
weightLbs: 70,
microchipped: true
});
return puppy;
} catch (error) {
if (error.name === 'SequelizeValidationError') {
// Handle validation errors
console.error("Validation error:", error.errors);
throw new Error("Invalid puppy data");
} else if (error.name === 'SequelizeUniqueConstraintError') {
// Handle unique constraint violations
console.error("Duplicate entry:", error.errors);
throw new Error("Puppy already exists");
} else {
// Handle other errors
console.error("Database error:", error);
throw new Error("Error creating puppy");
}
}
}
To verify your data insertion is working correctly:
1. Test direct database insertion:
// Using command line
sqlite3 db/dev.db "SELECT * FROM Puppies WHERE name = 'Trudy';"
2. Test API endpoints using Postman or curl:
// Example curl command
curl -X POST http://localhost:8000/puppies/create \
-H "Content-Type: application/json" \
-d '{"name":"Fred","ageYrs":2.1,"breed":"Boston Terrier","weightLbs":20,"microchipped":true}'
To deepen your understanding of Sequelize data insertion, try:
1. Implementing bulk creation for multiple records
2. Adding custom validation before insertion
3. Handling complex data relationships
4. Implementing transaction support for safer insertions
5. Creating more sophisticated error handling strategies