nodejs - sequelize.js 如何在不创建外键的情况下联表查询

3,181 阅读1分钟

问题:

外键关联会降低MySQL的并发量降低,sequelize.js想要联表查询,就必须创建关联关系。

但是用sequelize创建关联模型时,插件会自动为表创建关联的外键,这不是我们所期待的结果。

答案:

想要在不创建外键的情况下关联表,需要在创建表关联时加上一个属性constraints: false

下面是具体代码:

// 建立一对一关联关系
Blogs.belongsTo(Users, {
  // 创建外键 Blogs.userId -> Users.id
  foreignKey: 'userId',
  targetKey: 'id',
  constraints: false
})

// 建立一对多关联关系
Users.hasMany(Blogs, {
  foreignKey: 'userId',
  sourceKey: 'id',
  constraints: false
})

下面是完整的运行代码:

1. 创建Sequelize实例 - seq.js

const { Sequelize } = require('sequelize')

const sequelize = new Sequelize('koa2_weibo_db', 'root', 'root', {
  host: '127.0.0.1',
  dialect: 'mysql'
})

module.exports = sequelize

2. 创建模型 - model.js

const Sequelize = require('sequelize')
const seq = require('./seq.js')

// 创建 Users 模型,数据表名字是 Users
const Users = seq.define('users', {
    // id 会自动添加
    username: {
      type: Sequelize.STRING(45),
      allowNull: false
    },
    password: {
      type: Sequelize.STRING(45),
      allowNull: false
    },
    nickname: {
      type: Sequelize.STRING(45)
    }
  },
  {
    tableName: 'users',
    freezeTableName: true,
    // timestamps: false,
  })

// 创建 blogs
const Blogs = seq.define('blogs', {
    title: {
      type: Sequelize.STRING(45),
      allowNull: false
    },
    content: {
      type: Sequelize.TEXT,
      allowNull: false
    },
    userId: {
      type: Sequelize.INTEGER,
      allowNull: false
    }
  },
  {
    tableName: 'blogs',
    freezeTableName: true,
    // timestamps: false,
  }
)
// 建立一对一关联关系
Blogs.belongsTo(Users, {
  // 创建外键 Blogs.userId -> Users.id
  foreignKey: 'userId',
  targetKey: 'id',
  constraints: false
})

// 建立一对多关联关系
Users.hasMany(Blogs, {
  foreignKey: 'userId',
  sourceKey: 'id',
  constraints: false
})

module.exports = {
  Users,
  Blogs
}

3. 同步模型 - sync.js

const seq = require('./seq.js')

require('./model.js')

seq.sync({force: true})
  .then(() => {
    console.log('sync ok')
    process.exit()
  })

4. 创建模拟数据和关联关系 - create.js

下面为一对多关系

users.id -> blogs.userId

const { Blogs, Users } = require('./model.js')

;(async function () {
  // 创建用户
  const data1 = []
  console.time('start1')
  for (let i = 0; i < 1000; i++) {
    const zhangsan = await Users.create({
      username: 'zhangsan' + (i + 1),
      password: '123456',
      nickname: '张三' + (i + 1)
    })
    data1.push(zhangsan.dataValues)
  }
  console.log('create:users', data1)
  console.timeEnd('start1')

  // 创建博客
  const data2 = []
  console.time('start2')
  for (let i = 0; i < 10; i++) {
    const article = await Blogs.create({
      title: '文章' + (i + 1),
      content: '我是content' + (i + 1),
      userId: i + 1
    })
    data2.push(article.dataValues)
  }
  console.log('create:blogs', data2)
  console.timeEnd('start2')
  process.exit()
}())

5. 在不创建外键的情况下联表查询 - select.js

const { Blogs, Users } = require('./model.js')
const { resolve } = require('path')
const fs = require('fs')
// const Sequelize = require('Sequelize')

;(async function () {
  const zhangsan = await Users.findAll({
    attributes: ['id', 'username'],
    include: [
      {
        model: Blogs,
        required: true,
        attributes: ['title'],
      }
    ]
  })
  console.log(zhangsan.map(item => item.dataValues))
  // 保存数据,方便查看
  fs.writeFile(resolve(__dirname, 'data.json'), JSON.stringify(zhangsan.map(item => item.dataValues)), (err) => {
    if (err) throw err
    console.log('write ok')
  })
}())

6. 执行顺序

# 同步模型
$ node sync.js

# 插入假数据
$ node create.js

# 联表查询
$ node select.js