Node.js ORM - Sequelize
basic
Overview: ORM(Object Relation Mapping) based on Promise supports multiple databases, transactions, associations, etc
Installation: npm i sequelize mysql2 -S
Basic use:
const Sequelize = require("sequelize"); // Establish connection const sequelize = new Sequelize("kaikeba", "root", "admin", { host: "localhost", dialect: "mysql", operatorsAliases: false }); // Definition model const Fruit = sequelize.define("Fruit", { name: {type: Sequelize.STRING(20), allowNull: false}, price: {type: Sequelize.FLOAT, allowNull: false}, stock: {type: Sequelize.INTEGER, defaultValue: 0} }); // Synchronize database, force: true will delete the existing table Fruit.sync().then(() => { // Add test data return Fruit.create({name: "Banana", price: 3.5}); }).then(() => { // Query Fruit.findAll().then(fruits => { console.log(JSON.stringify(fruits)); }); });
What is forced synchronization? How to use it? (resets existing tables)
Fruit.sync({force: true})
Table is generated by default. How to remove it?
const Fruit = sequelize.define("Fruit", {}, { timestamps: false });
Specify table name: freesetablename: true or tableName:'xxx'
Set the former to take modelName as the table name; set the latter to take its value as the table name.
What's the use of getters & setters? : can be used to define pseudo properties or protection properties mapped to database fields
// Defined as part of an attribute name: { type: Sequelize.STRING, allowNull :false, get(){ const fname = this.getDataValue("name"); const price = this.getDataValue("price"); const stock = this.getDataValue("stock"); return `${fname}(Price:¥${price} Stock: ${stock}kg)`; } } // Define as model option { getterMethods:{ amount() { return this.getDataValue("stock") + "kg"; } }, setterMethods:{ amount(val) { const idx = val.indexOf('kg'); const v = val.slice(0, idx); this.setDataValue('stock', v); } } } // Trigger setterMethods through model instance Fruit.findAll().then(fruits => { console.log(JSON.stringify(fruits)); // Modify amount and trigger setterMethods fruits[0].amount = '150kg'; fruits[0].save(); });
How to verify? : the format and content of model fields can be verified through the verification function, and the verification will run automatically when creating, updating and saving
price: { validate: { isFloat: {msg: "Please enter a number for the price field"}, min: {args: [0], msg:"Price field must be greater than 0"} } }, stock: { validate: { isNumeric: {msg: "Please enter a number for the inventory field"} } }
How to extend the model? : model instance method or class method extension model can be added
// Add class level method Fruit.classify = function (name) { const tropicFruits = ['Banana', 'Mango', 'Coconut']; // Tropical fruit return tropicFruits.includes(name) ? 'Tropical fruits':'Other fruits'; }; // Add instance level method Fruit.prototype.totalPrice = function (count) { return (this.price * count).toFixed(2); }; // Using class methods ['Banana', 'Strawberry'].forEach(f => console.log(f + 'yes' + Fruit.classify(f))); // Use instance method Fruit.findAll().then(fruits => { const [f1] = fruits; console.log(`Buy 5 kg${f1.name}Need¥${f1.totalPrice(5)}`); });
Additions and deletions
1 increase
ret = await Fruit.create({ name: "Banana", price: 3.5 })
2 delete
// Mode 1 Fruit.findOne({ where: { id: 1 } }).then(r => r.destroy()); // Mode 2 Fruit.destroy({ where: { id: 1 } }).then(r => console.log(r));
3 changes
// Mode 1 Fruit.findById(1).then(fruit => { fruit.price = 4; fruit.save().then(() => console.log('update!!!!')); }); // Mode 2 Fruit.update({price: 4}, {where: {id: 1}}).then(r => { console.log(r); console.log('update!!!!') })
4 check
// Query by attributes Fruit.findOne({where: {name: "Banana"}}).then(fruit => { // fruit is the first match, null if not console.log(fruit.get()); }); // Get data and total number Fruit.findAndCountAll().then(result => { console.log(result.count); console.log(result.rows.length); }); // Query Operators const Op = Sequelize.Op; Fruit.findAll({ // where: { price: { [Op.lt]:4 }, stock: { [Op.gte]: 100 } } where: {price: {[Op.lt]: 4, [Op.gt]: 2}} }).then(fruits => { console.log(fruits.length); }); // Or statement Fruit.findAll({ // where: { [Op.or]:[{price: { [Op.lt]:4 }}, {stock: { [Op.gte]: 100 }}] } where: {price: {[Op.or]: [{[Op.gt]: 3}, {[Op.lt]: 2}]}} }).then(fruits => { console.log(fruits[0].get()); }); // paging Fruit.findAll({offset: 0, limit: 2,}) // sort Fruit.findAll({order: [['price', 'DESC']],}) // polymerization setTimeout(() => { Fruit.max("price").then(max => { console.log("max", max) }) Fruit.sum("price").then(sum => { console.log("sum", sum); }); }, 500)
4-2 associated query
Relation
//1:N relationship const Player = sequelize.define('player', {name: Sequelize.STRING}); const Team = sequelize.define('team', {name: Sequelize.STRING}); // teamId will be added to Player table as foreign key Player.belongsTo(Team);// 1 end building relationship Team.hasMany(Player); // N-terminal relationship // synchronization sequelize.sync({force: true}).then(async () => { await Team.create({name: 'rocket'}); await Player.bulkCreate([{name: 'Harden', teamId: 1}, {name: 'Paul', teamId: 1}]); // 1 end Association query const players = await Player.findAll({include: [Team]}); console.log(JSON.stringify(players, null, '\t')); // N end Association query const team = await Team.findOne({where: {name: 'rocket'}, include: [Player]}); console.log(JSON.stringify(team, null, '\t')); }); // Many to many relationship const Fruit = sequelize.define("fruit", {name: Sequelize.STRING}); const Category = sequelize.define("category", {name: Sequelize.STRING}); Fruit.FruitCategory = Fruit.belongsToMany( Category, {through: "FruitCategory"} );