Sequelize 多對多的建立、查詢、更新

前言,最近在研究nodeJs,新手上車,使用mysql的ORM庫Sequelize,其中多對多,belongsToMany的建立、查詢、更新摸索了幾天,寫下如下。
既然使用Sequelize,也就是不想原生sql語句,因此本文對原生sql大佬毫無做用,對Sequelize大佬毫無做用(反倒但願大家指點一二),只但願對剛上手Sequelize的胖友多少有點借鑑意義。
Sequelize的安裝、連接mysql、簡單的增刪改查我就不累贅了,處處能搜索到,如下只針對belongsToMany。node

咱們假設有這樣的一個場景,文章(Post)能夠有多個標籤(Tag),一樣,一個Tag也能夠對應多個Post,咱們須要一張關聯表PostTag來記錄Post和Tag之間的關係。mysql

1、表結構

//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
            })

2、創建關聯關係

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方法。學習

3、建立

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}]
     }

圖片描述
圖片描述圖片描述

4、關聯查詢

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

5、更新

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
    }

6、事務

多表更新中,咱們總擔憂那一步出錯,致使後期難以維護,這裏可使用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的建立、更新、查詢有更好建議的歡迎留言,我也在摸索中。

相關文章
相關標籤/搜索