Sequelize Associations:如何在创建子模型时更新父模型?
Sequelize Associations: How to update parent model when creating child?
看来我误解了 sequelize .hasMany()
和 .belongsTo()
关联以及如何在服务中使用它们。我有两个型号:
const User = db.sequelize.define("user", {
uid: { /*...*/ },
createdQuestions: {
type: db.DataTypes.ARRAY(db.DataTypes.UUID),
unique: true,
allowNull: true,
},
});
const Question = db.sequelize.define("question", {
qid: { /*...*/ },
uid: {
type: db.DataTypes.TEXT,
},
});
鉴于一个用户可以有很多问题,而每个问题只属于一个用户,我有以下关联:
User.hasMany(Question, {
sourceKey: "createdQuestions",
foreignKey: "uid",
constraints: false,
});
Question.belongsTo(User, {
foreignKey: "uid",
targetKey: "createdQuestions",
constraints: false,
});
我想要实现的是:创建问题对象后,qid
应该驻留在 "createdQuestions"
下的用户对象中 - 正如 uid
驻留在uid
下的问题对象。我认为 sequelize 关联会为我做的是保存个人调用和更新用户对象。有对应的方法吗?我目前拥有的是:
const create_question = async (question_data) => {
const question = { /*... question body containing uid and so forth*/ };
return new Promise((resolve, rejected) => {
Question.sync({ alter: true }).then(
async () =>
await db.sequelize
.transaction(async (t) => {
const created_question = await Question.create(question, {
transaction: t,
});
})
.then(() => resolve())
.catch((e) => rejected(e))
);
});
};
但这只会创建一个问题对象,不会更新用户。我在这里错过了什么?
您的关系是一对多关系。一个用户可以有多个问题。在 SQL 中,这种关系是通过向 Question 添加一个名为 userId 或 Uid 的属性来建模的。在 Sequelize 中,这将通过像这样的 hasMany 或 BelongsTo 来实现:
User.hasMany(Question)
Question.belongsTo(User, {
foreignKey: 'userId',
constraints: false
})
换句话说,我认为您不需要 User 下的 CreatedQuestions
属性。只需要一个外键来建模 oneToMany 关系。
现在创建新问题时,只需要这样添加userId
createNewQuestion = async (userId, title, body) => {
const question = await Question.create({
userId: userId, // or just userId
title: title, // or just title
body: body // or just body
})
return question
}
记住,我们不在SQL中存储数组。即使我们能找到办法去做,那也不是我们所需要的。总有更好的方法。
在 SQL
中建模一对多关系
SQL 对比没有SQL
在 SQL 中,与 NoSQL 中的情况相反,每个属性都有固定的数据类型和固定的位数限制。在创建新的 table:
时,SQL 命令表明了这一点
CREATE TABLE teachers (
name VARCHAR(32),
department VARCHAR(64),
age INTEGER
);
这背后的原因是允许我们通过知道每一行的长度来轻松地访问数据库中的任何属性。在我们的例子中,每一行都需要 space 来存储:
32 字节(姓名) + 64 字节(部门) + 4 字节(年龄) = 100 字节
这是关系数据库中的一项非常强大的功能,因为它可以将检索数据所需的时间降至恒定时间,因为我们知道在哪里每条数据都位于内存中。
一对多关系:案例研究
现在,让我们考虑一下我们有这 3 tables
假设我们要在 classes 和 [=54= 之间创建一个 一对多 关系]teachers 老师可以给很多 classes.
我们可以这样想。但是,由于两个主要原因,此模型是不可能的:
- 这将使我们失去恒定时间检索,因为我们不再知道列表的大小
- 我们担心为列表属性提供的 space 数量不足以用于未来的数据。假设我们分配了 10 个 class 所需的 space,而我们最终得到一位老师给出了 11 个 class。这将促使我们重新创建数据库以增加列大小。
另一种方式是这样的:
虽然这种方法将解决列大小受限的问题,但我们不再拥有单一的真实来源。相同的数据被复制并存储多次。
这就是为什么对于这种一对多关系,我们需要将教师的 Id 存储在此 class table.
中
这样,我们仍然可以找到所有 class老师可以教 运行
SELECT *
FROM classes
WHERE teacherID = teacher_id
我们将避免前面讨论的所有问题。
看来我误解了 sequelize .hasMany()
和 .belongsTo()
关联以及如何在服务中使用它们。我有两个型号:
const User = db.sequelize.define("user", {
uid: { /*...*/ },
createdQuestions: {
type: db.DataTypes.ARRAY(db.DataTypes.UUID),
unique: true,
allowNull: true,
},
});
const Question = db.sequelize.define("question", {
qid: { /*...*/ },
uid: {
type: db.DataTypes.TEXT,
},
});
鉴于一个用户可以有很多问题,而每个问题只属于一个用户,我有以下关联:
User.hasMany(Question, {
sourceKey: "createdQuestions",
foreignKey: "uid",
constraints: false,
});
Question.belongsTo(User, {
foreignKey: "uid",
targetKey: "createdQuestions",
constraints: false,
});
我想要实现的是:创建问题对象后,qid
应该驻留在 "createdQuestions"
下的用户对象中 - 正如 uid
驻留在uid
下的问题对象。我认为 sequelize 关联会为我做的是保存个人调用和更新用户对象。有对应的方法吗?我目前拥有的是:
const create_question = async (question_data) => {
const question = { /*... question body containing uid and so forth*/ };
return new Promise((resolve, rejected) => {
Question.sync({ alter: true }).then(
async () =>
await db.sequelize
.transaction(async (t) => {
const created_question = await Question.create(question, {
transaction: t,
});
})
.then(() => resolve())
.catch((e) => rejected(e))
);
});
};
但这只会创建一个问题对象,不会更新用户。我在这里错过了什么?
您的关系是一对多关系。一个用户可以有多个问题。在 SQL 中,这种关系是通过向 Question 添加一个名为 userId 或 Uid 的属性来建模的。在 Sequelize 中,这将通过像这样的 hasMany 或 BelongsTo 来实现:
User.hasMany(Question)
Question.belongsTo(User, {
foreignKey: 'userId',
constraints: false
})
换句话说,我认为您不需要 User 下的 CreatedQuestions
属性。只需要一个外键来建模 oneToMany 关系。
现在创建新问题时,只需要这样添加userId
createNewQuestion = async (userId, title, body) => {
const question = await Question.create({
userId: userId, // or just userId
title: title, // or just title
body: body // or just body
})
return question
}
记住,我们不在SQL中存储数组。即使我们能找到办法去做,那也不是我们所需要的。总有更好的方法。
在 SQL
中建模一对多关系SQL 对比没有SQL
在 SQL 中,与 NoSQL 中的情况相反,每个属性都有固定的数据类型和固定的位数限制。在创建新的 table:
时,SQL 命令表明了这一点CREATE TABLE teachers (
name VARCHAR(32),
department VARCHAR(64),
age INTEGER
);
这背后的原因是允许我们通过知道每一行的长度来轻松地访问数据库中的任何属性。在我们的例子中,每一行都需要 space 来存储:
32 字节(姓名) + 64 字节(部门) + 4 字节(年龄) = 100 字节
这是关系数据库中的一项非常强大的功能,因为它可以将检索数据所需的时间降至恒定时间,因为我们知道在哪里每条数据都位于内存中。
一对多关系:案例研究
现在,让我们考虑一下我们有这 3 tables
假设我们要在 classes 和 [=54= 之间创建一个 一对多 关系]teachers 老师可以给很多 classes.
我们可以这样想。但是,由于两个主要原因,此模型是不可能的:
- 这将使我们失去恒定时间检索,因为我们不再知道列表的大小
- 我们担心为列表属性提供的 space 数量不足以用于未来的数据。假设我们分配了 10 个 class 所需的 space,而我们最终得到一位老师给出了 11 个 class。这将促使我们重新创建数据库以增加列大小。
另一种方式是这样的:
虽然这种方法将解决列大小受限的问题,但我们不再拥有单一的真实来源。相同的数据被复制并存储多次。
这就是为什么对于这种一对多关系,我们需要将教师的 Id 存储在此 class table.
中这样,我们仍然可以找到所有 class老师可以教 运行
SELECT *
FROM classes
WHERE teacherID = teacher_id
我们将避免前面讨论的所有问题。