我正在使用sequelize include来关联接下来的三个模型
“moldsets”有很多“molds”,“molds”有很多“moldstatus”
// moldsets.model.js
const Sequelize = require("sequelize");
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get("sequelizeClient");
const moldsets = sequelizeClient.define(
"moldsets",
{
name: {
type: DataTypes.STRING,
allowNull: false,
},
vendor: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.STRING,
allowNull: false,
},
number_of_blanks: {
type: DataTypes.INTEGER,
allowNull: false,
},
number_of_blows: {
type: DataTypes.INTEGER,
allowNull: false,
},
date_of_reception: {
type: DataTypes.DATE,
allowNull: false,
},
date_of_scrap: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
hooks: {
beforeCount(options) {
options.raw = true;
},
},
}
);
// eslint-disable-next-line no-unused-vars
moldsets.associate = function (models) {
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
const { molds } = models;
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
moldsets.hasMany(molds, { foreignKey: "moldsetId" });
};
return moldsets;
};
//molds.model.js
const Sequelize = require("sequelize");
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get("sequelizeClient");
const molds = sequelizeClient.define(
"molds",
{
number: {
type: DataTypes.INTEGER,
allowNull: false,
},
kind: {
type: DataTypes.STRING,
allowNull: false,
},
moldsetId: {
type: DataTypes.INTEGER,
allowNull: false,
},
numberOfTotalGobs: {
type: DataTypes.INTEGER,
allowNull: false,
},
statusId: {
type: DataTypes.INTEGER,
allowNull: false,
},
note: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
hooks: {
beforeCount(options) {
options.raw = true;
},
},
}
);
// eslint-disable-next-line no-unused-vars
molds.associate = function (models) {
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
console.log(models);
const { moldsets, moldstatus } = models;
molds.belongsTo(moldsets);
molds.hasMany(moldstatus, { as: "status" });
};
return molds;
};
// moldstatus.model.js
const Sequelize = require("sequelize");
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get("sequelizeClient");
const moldstatus = sequelizeClient.define(
"moldstatus",
{
moldId: {
type: DataTypes.INTEGER,
allowNull: false,
},
status: {
type: DataTypes.STRING,
allowNull: false,
},
startdate: {
type: DataTypes.DATE,
allowNull: false,
},
enddate: {
type: DataTypes.DATE,
allowNull: true,
},
note: {
type: DataTypes.STRING,
allowNull: true,
},
lineId: {
type: DataTypes.INTEGER,
allowNull: false,
},
section: {
type: DataTypes.STRING,
allowNull: false,
},
defect: {
type: DataTypes.STRING,
allowNull: true,
},
numberOfGobs: {
type: DataTypes.INTEGER,
allowNull: false,
},
operatorId: {
type: DataTypes.INTEGER,
allowNull: false,
},
},
{
hooks: {
beforeCount(options) {
options.raw = true;
},
},
}
);
// eslint-disable-next-line no-unused-vars
moldstatus.associate = function (models) {
// Define associations here
// See http://docs.sequelizejs.com/en/latest/docs/associations/
const { molds } = models;
moldstatus.belongsTo(molds, { foreignKey: "statusId" });
};
return moldstatus;
};
但是当我查询模具组时(我使用的是feathersjs,所以我在之前的查找钩子中使用它)
const related = async (context) => {
const sequelize = context.app.get("sequelizeClient");
const { molds, moldstatus } = sequelize.models;
context.params.sequelize = {
include: [
//{ all: true, nested: true },
{
model: molds,
attributes: ["number", "statusId"],
required: false,
order: [[molds, "number", "ASC"]],
include: [
{
model: moldstatus,
as: "status",
required: false,
attributes: ["status"],
//order: [[moldstatus, "created_at", "DESC"]],
},
],
raw: false,
},
],
raw: false,
};
return context;
};
module.exports = {
before: {
all: [
authenticate("jwt"),
(context) => {
related(context);
},
],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: [],
},
};
结果是我获得了所有模具组及其模具,但我仅获得了每个模具组中第一个模具的第一个模具状态(其他模具为空数组) 我尝试将 raw 设置为 true,但我仍然只获得每个模具组中第一个模具的状态...
//result
[{
"id": 2,
"name": "fruity250ml1",
"vendor": "jacob",
"status": "mounted",
"number_of_blanks": 30,
"number_of_blows": 28,
"date_of_reception": "2021-04-26T13:22:00.000Z",
"date_of_scrap": null,
"createdAt": "2021-04-26T13:22:00.000Z",
"updatedAt": "2021-04-26T13:22:00.000Z",
"molds": [
{
"number": 1,
"statusId": 3,
"status": [
{
"status": "mounted"
}
]
},
{
"number": 2,
"statusId": 4,
"status": []
}
],
"mounted": null
},
{
"id": 1,
"name": "seles250ml1",
"vendor": "omco",
"status": "avalible",
"number_of_blanks": 30,
"number_of_blows": 28,
"date_of_reception": "2021-07-26T13:22:00.000Z",
"date_of_scrap": null,
"createdAt": "2021-07-26T13:22:00.000Z",
"updatedAt": "2021-07-26T13:22:00.000Z",
"molds": [
{
"number": 2,
"statusId": 2,
"status": []
},
{
"number": 3,
"statusId": 3,
"status": []
},
{
"number": 1,
"statusId": 3,
"status": [
{
"status": "avalible"
}
]
}
]
}
]
首先,如果您明确指定某个关联中的外键字段,您也应该为反向关联指定它:
moldsets.hasMany(molds, { foreignKey: "moldsetId" });
...
molds.belongsTo(moldsets, { foreignKey: "moldsetId" });
molds.hasMany(moldstatus, { as: "status", foreignKey: "statusId" });
...
moldstatus.belongsTo(molds, { foreignKey: "statusId" });
并且您为
molds.hasMany(moldstatus
指定了不正确的外键字段,因此上述关联应如下所示:
molds.hasMany(moldstatus, { as: "status", foreignKey: "moldId" });
...
moldstatus.belongsTo(molds, { foreignKey: "moldId" });
对于仍然遇到问题的其他人,就我而言,我使用的是 Postgres DB,它倾向于截断关系标识符/列名称。检查调试日志,我可以看到sequelize正在生成我想要的查询。使用
raw: true
设置,我可以看到 Sequelize 也能够获得正确的“原始”结果,就像我使用 DBeaver 或 PgAdmin 查询它一样。
所以问题在于 Sequelize 如何将这些行整理成嵌套对象。通过反复试验,我发现这是两个罪魁祸首的组合:
JOIN
中,Postgres 会默默地(但 DBeaver 不会默默地)截断标识符名称,即查询的表和列别名。例如SELECT super_long_column_name AS super_long_table_name.super_long_column_name
FROM super_long_table_name;
-- # super_long_table_name.super_long_column_name will be truncated to something like super_long_table_name.supe
-- # Not sure about the exact char limit.
我们所做的解决方案或解决方法可能是在包含的模型中使用较短的别名。例如
const nestedObject = await Table1.findAll({
include: [
{
model: SuperLongTableName,
as: "super_long_table_name"
},
// ...
]
});
更改为
const nestedObject = await Table1.findAll({
include: [
{
model: SuperLongTableName,
as: "sltn"
},
// ...
]
});
然后就成功了。希望这有帮助!