sequelize 仅返回第一行(通过包含关联)

问题描述 投票:0回答:2

我正在使用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"
                }
            ]
        }
    ]
}
]  

数据库: 模具: molds 模具状态: moldstatus 模具组: moldsets

postgresql sequelize.js
2个回答
0
投票

首先,如果您明确指定某个关联中的外键字段,您也应该为反向关联指定它:

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" });

0
投票

对于仍然遇到问题的其他人,就我而言,我使用的是 Postgres DB,它倾向于截断关系标识符/列名称。检查调试日志,我可以看到sequelize正在生成我想要的查询。使用

raw: true
设置,我可以看到 Sequelize 也能够获得正确的“原始”结果,就像我使用 DBeaver 或 PgAdmin 查询它一样。

所以问题在于 Sequelize 如何将这些行整理成嵌套对象。通过反复试验,我发现这是两个罪魁祸首的组合:

  1. 由于我们有很长的表名和列名(每个名称至少 4 个单词),并且 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.
  1. 由于某些标识符被截断,不确定是否仅特定于外键和主键,Sequelize 在将数据整理到嵌套对象中时遇到问题。

我们所做的解决方案或解决方法可能是在包含的模型中使用较短的别名。例如

const nestedObject = await Table1.findAll({
  include: [
    {
      model: SuperLongTableName,
      as: "super_long_table_name"
    },
    // ...
  ]
});

更改为

const nestedObject = await Table1.findAll({
  include: [
    {
      model: SuperLongTableName,
      as: "sltn"
    },
    // ...
  ]
});

然后就成功了。希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.