前言,最近在研究nodeJs,新手上車,使用mysql的ORM庫Sequelize,其中多對多,belongsToMany的建立、查詢、更新摸索了幾天,寫下如下。
既然使用Sequelize,也就是不想原生sql語句,因此本文對原生sql大佬毫無做用,對Sequelize大佬毫無做用(反倒但願大家指點一二),只但願對剛上手Sequelize的胖友多少有點借鑑意義。
Sequelize的安裝、連接mysql、簡單的增刪改查我就不累贅了,處處能搜索到,如下只針對belongsToMany。node
咱們假設有這樣的一個場景,文章(Post)能夠有多個標籤(Tag),一樣,一個Tag也能夠對應多個Post,咱們須要一張關聯表PostTag來記錄Post和Tag之間的關係。mysql
//tag表sql
sequelize.define('tag', { name: { type: DataTypes.STRING(20), allowNull: false }, createdAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm:ss'); } }, updatedAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('updatedAt')).format('YYYY-MM-DD HH:mm:ss'); } } }, { freezeTableName: true })
//Post 表promise
sequelize.define('post', { name: { type: DataTypes.STRING(20), allowNull: false }, createdAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm:ss'); } }, updatedAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('updatedAt')).format('YYYY-MM-DD HH:mm:ss'); } } }, { freezeTableName: true })
//PostTag表async
sequelize.define('postTag', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true }, postId: { type: DataTypes.INTEGER, allowNull:false, unique: 'postTag' }, tagId:{ type: DataTypes.INTEGER, unique: 'postTag', allowNull:false, references: null }, createdAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm:ss'); } }, updatedAt: { type: DataTypes.DATE, get() { return moment(this.getDataValue('updatedAt')).format('YYYY-MM-DD HH:mm:ss'); } } }, { freezeTableName: true })
const Sequelize = require('../config/db')
const PostTag = Sequelize.import('../schema/postTag.js')
const Tag = Sequelize.import('../schema/tag.js')
const Post = Sequelize.import('../schema/post.js')
// 表須要先sync 請自行處理,
//例如 PostTag.sync({force: false});post
Post.belongsToMany(Tag, { through: { model: PostTag, unique: false, }, foreignKey: 'postId', //經過外鍵postId constraints: false }); Tag.belongsToMany(Post, { through: { model: PostTag, unique: false, }, foreignKey: 'tagId', //經過外鍵tagId constraints: false });
建議關聯關係以後,Post會自動添加addTags、getTags、setTags方法。
Tag會自動添加addPosts、getPosts、setPosts方法。學習
static async create(data) { //例如咱們tag表有2條數據,[{id:1,name:'標籤1'},{id:2,name:'標籤2'}] //傳遞進來的data = {name:'文章1',tagIds:[1,2]} let newPost = await Post.create({name: data.name}); //返回建立的post對象 let tags = await Tag.findAll({where: {id: data['tagIds']}})//找到對應的tagId對象 await newPost.setTags(tags) //經過setTags方法在postTag表添加記錄 return true //以上操做會給post表建立一條新的記錄,{id:1,name:'文章1'} //給postTag表添加2條記錄,[{id:1,postId:1,tagId:1},{id:2,post:1,tagId:2}] }
static async allPost() { return await Post.findAll({ include: [ {model: Tag, attributes: ['id', 'name']} ] }); } //查詢結果 { "code": 200, "msg": "查詢成功!", "data": [ { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 1, "name": "文章1", "tags": [ { "createdAt": "2018-12-10 13:21:37", "updatedAt": "2018-12-10 13:21:37", "id": 1, "name": "標籤1", "postTag": { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 1, "postId": 1, "tagId": 1 } }, { "createdAt": "2018-12-10 13:21:37", "updatedAt": "2018-12-10 13:21:37", "id": 2, "name": "標籤2", "postTag": { "createdAt": "2018-12-10 13:18:11", "updatedAt": "2018-12-10 13:18:11", "id": 2, "postId": 1, "tagId": 2 } } ] } ]
}ui
static async updatePost(id, data) { //id爲須要修改的ID,data = {name:'修改文章',tagIds:[1]} let tags = await Tag.findAll({where: {id: data['tagIds']}}) Post.findByPk(id).then(function (post) { post.update({name: data.name}) post.setTags(tags) }) return true }
多表更新中,咱們總擔憂那一步出錯,致使後期難以維護,這裏可使用transaction事務來處理。一旦那一步出錯,自動回滾。我拿建立那一步寫個範例。this
static async create(data) { let tags = await Tag.findAll({where: {id: data['tagIds']}}) return Sequelize.transaction(function (t) { return Post.create({name: data.name}, {transaction: t}) .then(function (post) { return post.setTags(tags, {transaction: t}) }); }).then(function (result) { // 事務已被提交 result 是 promise 鏈返回到事務回調的結果 }).catch(function (err) { // 事務已被回滾 throw 拋出錯誤 throw err; }); }
//關於transaction的更具體內容,能夠查看Sequelize文檔(儘管是全英 :))。spa
以上,僅供你們學習參考,如對 belongsToMany的建立、更新、查詢有更好建議的歡迎留言,我也在摸索中。