使用Sequelize的多对多关系的简单示例

Ion*_*zău 12 javascript mysql many-to-many node.js sequelize.js

我正在尝试使用Sequelize构建表之间多对多关系的简单示例.然而,这似乎比我预期的更棘手.

这是我目前的代码(该./db.js文件导出Sequelize连接实例).

const Sequelize = require("sequelize");
const sequelize = require("./db");

var Mentee = sequelize.define('mentee', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    name: {
        type: Sequelize.STRING
    }
});

var Question = sequelize.define('question', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    text: {
        type: Sequelize.STRING
    }
});

var MenteeQuestion = sequelize.define('menteequestion', {
//    answer: {
//        type: Sequelize.STRING
//    }
});

// A mentee can answer several questions
Mentee.belongsToMany(Question, { as: "Questions", through: MenteeQuestion });

// And a question can be answered by several mentees
Question.belongsToMany(Mentee, { as: "Mentees", through: MenteeQuestion });

let currentQuestion = null;
Promise.all([
    Mentee.sync({ force: true })
  , Question.sync({ force: true })
  , MenteeQuestion.sync({ force: true })
]).then(() => {
    return Mentee.destroy({where: {}})
}).then(() => {
    return Question.destroy({ where: {} })
}).then(() => {
    return Question.create({
        text: "What is 42?"
    });
}).then(question => {
    currentQuestion = question;
    return Mentee.create({
        name: "Johnny"
    })
}).then(mentee => {
    console.log("Adding question");
    return mentee.addQuestion(currentQuestion);
}).then(() => {
    return MenteeQuestion.findAll({
        where: {}
      , include: [Mentee]
    })
}).then(menteeQuestions => {
    return MenteeQuestion.findAll({
        where: {
            menteeId: 1
        }
      , include: [Mentee]
    })
}).then(menteeQuestion => {
    console.log(menteeQuestion.toJSON());
}).catch(e => {
    console.error(e);
});
Run Code Online (Sandbox Code Playgroud)

运行时,我得到:

无法添加外键约束

我认为这是因为id类型 - 但我不知道为什么它出现以及我们如何解决它.

当前一个不出现时出现的另一个错误是:

执行(默认):INSERT INTO menteequestions(menteeId,questionId,createdAt,updatedAt)VALUES(2,1, '2017年3月17日6点18分01秒', '2017年3月17日6点18分01秒');

错误:受指导者与menteequestion无关!

另外,我得到的另一个错误 - 我认为这是因为force:truein sync-is:

DROP TABLE IF EXISTS mentees;

ER_ROW_IS_REFERENCED:无法删除或更新父行:外键约束失败

怎么解决这些?

同样,我只需要一个多对多crud操作的最小例子(在这种情况下只是插入和读取),但这似乎超出了我的理解.用这两天挣扎了两天.

pio*_*ias 15

迁移

我建议你使用sequelize 迁移代替sync()每个模型.有一个模块--sequelize.cli,可以让您轻松管理迁移和种子.它以某种方式,强制通过创建初始化文件的项目结构index.js/models项目的目录.它假设您的所有模型定义都在此目录中.该脚本遍历所有模型文件(每个模型定义在单独的文件中,例如mentee.js,question.js)并执行sequelize.import()以便将这些模型分配给续集实例 - 这使您可以稍后通过sequelize[modelName]例如访问它们sequelize.question.

注:当创建迁移文件记住时间戳字段- createdAt,updatedAt并最终deletedAt.

同步

我个人sync()只在运行测试时使用- 这可能分三步显示

  1. 执行sequelize.sync({ force: true })以同步所有模型
  2. 运行一些数据库seeds(也可以通过sequelize-cli),
  3. 运行测试.

这非常舒适,因为允许您在运行测试之前清理数据库,并且为了区分开发和测试,测试可以使用不同的数据库,例如project_test,以便开发数据库保持不变.

许多一对多

现在让我们继续讨论你的问题 - m:n两个模型之间的关系.首先,由于您执行的事实Promise.all()时,sync可以在不同的顺序,你在里面添加的功能运行.为了避免这种情况,我建议你使用promise的mapSeries功能Bluebird,Sequelize使用和公开sequelize.Promise(这也是你上次删除父行的错误的原因 - 你试图删除mentees引用的内容menteequestion).

sequelize.Promise.mapSeries([
    Mentee.sync({ force: true })
  , Question.sync({ force: true })
  , MenteeQuestion.sync({ force: true })
], (model) => { return model.destroy({ where: {} }); }).then(() => {

});
Run Code Online (Sandbox Code Playgroud)

第一个参数mapSeries是promises数组,但第二个参数是一个函数,它与每个先前定义的promise的结果一起运行.由于Model.sync()模型本身的结果,我们可以model.destroy()在每次迭代时执行.

之后,您可以通过一些数据插入数据库create(),就像在示例中一样.现在是时候修复错误了:受指导者与menteequestion无关!错误.这是因为你有关联的MenteeQuestion,但之间不存在关联MenteeQuestionMentee(或Question).为了解决这个问题belongsToMany,您可以添加

MenteeQuestion.belongsTo(Mentee, { foreignKey: 'menteeId' });
MenteeQuestion.belongsTo(Question, { foreignKey: 'questionId' });
Run Code Online (Sandbox Code Playgroud)

现在您可以include: [Mentee, Question]在查询时添加MenteeQuestion.你也会在做的时候运行另一个错误toJSON(),因为你这样做findAll会返回实例数组.你可以做到forEach()

menteeQuestions.forEach(menteeQuestion => {
    console.log(menteeQuestion.toJSON());
});
Run Code Online (Sandbox Code Playgroud)