Sequelize - 如何使用 sequelize 将 csv 数据插入 mysql 中的多个表

Sequelize - How to insert csv data into multiple tables in mysql using sequelize

我在用什么

node.js, express, sequelize 6.3.3, fast-csv 4.3.1 and mysql database.

我有什么

我有一个包含以下 headers 和数据的 CSV 文件。

no, name, email, township, father_name, father_phone, mother_name, mother_phone, parent_township

在这个 CSV 中,我有两种类型的数据:studentsparents

在我的 MySQL 数据库中,我有三个 table:

students, parents and townships 

同学们table:

id, name, email, township_id

Parents table:

id, student_id, father_name, father_phone, mother_name, mother_phone, parent_township_id

乡镇table:

id, name

我做了什么

我用 fast-csv npm 包读取 CSV,代码如下。

let csvData = [];

fs.createReadStream(req.file.path)
    .pipe(
      csv.parse({
        ignoreEmpty: true,
        trim: true,
        skipLines: 6,
      })
    )
    .on("error", (error) => console.error(error))
    .on("data", (row) => {
      csvData.push(getHeaders(_.compact(row), csvStudentDataEntryFields));
    })
    .on("end", () => {
      fs.unlinkSync(req.file.path);

      const data = csvData.map((data) => {
        const student = _.pick(data, studentFields);
        const parent = _.pick(data, parentFields);
        return [student, parent];
      });

      return res.status(201).send({
        status: "success",
        data,
      });
    });

我得到了什么

通过上面的代码,我得到了 data 以下值。

[
    [ // row 1 from CSV
        {
            "name": "John",
            "email": "john@gmail.com",
            "township": "NYC",
        },
        {
            "fatherName": "Smith",
            "fatherPhone": "9111111111",
            "motherName": "Mary",
            "motherPhone": "9111111111",
            "parentTownship": "NYC"
         }
    ],
    [ // row 2 from CSV
        {
            "name": "Cutter",
            "email": "cutter@gmail.com",
            "township": "NYC",
        },
        {
            "fatherName": "Laseli",
            "fatherPhone": "9111111111",
            "motherName": "Mary",
            "motherPhone": "9111111111",
            "parentTownship": "NYC"
        }
    ]
]

我想要的

我想将 data 中的 row 1row 2 存储到数据库中相应的 table 中。

问题

我想我需要用真实 ID 替换那些 township 文本数据 因为我有如上所述的外键。

如何实现?我想在数据库级别进行。我不想在单独的 js 模块中查找那个乡镇名称的 id

已更新

学生模型

class Student extends Model {
    static associate(models) {
      Student.belongsTo(models.Township, {
        foreignKey: "townshipId",
        as: "township",
        targetKey: "townshipId",
      });

     Student.hasOne(models.Parent, {
        foreignKey: "studentId",
        as: "parent",
        sourceKey: "studentId",
      });
    }
  }

Parent型号

class Parent extends Model {
    static associate(models) {
      Parent.belongsTo(models.Student, {
        foreignKey: "studentId",
        as: "student",
        targetKey: "studentId",
      });

      Parent.belongsTo(models.Township, {
        foreignKey: "parentTownshipId",
        as: "township",
        targetKey: "townshipId",
      });
    }
  }

乡镇模式

class Township extends Model {
    static associate(models) {
      Township.hasMany(models.Student, {
        foreignKey: "townshipId",
        as: "township",
        sourceKey: "townshipId",
      });

      Township.hasMany(models.Parent, {
        foreignKey: "townshipId",
        as: "parentTownship",
        sourceKey: "townshipId",
      });
    }
  }

更新:

在我的控制器中,

let std = await models.Student.create(
    {
        nameEn: "John",
        email: "john@gmail.com",
        townshipId: 1,
        parent: [{ ...d[1], parentTownshipId: 1 }],
    },
    { include: ["parent"] }
);

我想你可以把所有的关系都插入在一起。

这来自续集文档

const amidala = await User.create({
  username: 'p4dm3',
  points: 1000,
  profiles: [{
    name: 'Queen',
    User_Profile: {
      selfGranted: true
    }
  }]
}, {
  include: Profile
});

const result = await User.findOne({
  where: { username: 'p4dm3' },
  include: Profile
});

console.log(result);

设置源密钥

 const Foo = sequelize.define('foo', {
  name: { type: DataTypes.TEXT, unique: true }
}, { timestamps: false });
const Bar = sequelize.define('bar', {
  title: { type: DataTypes.TEXT, unique: true }
}, { timestamps: false });
const Baz = sequelize.define('baz', { summary: DataTypes.TEXT }, { timestamps: false });
Foo.hasOne(Bar, { sourceKey: 'name', foreignKey: 'fooName' });
Bar.hasMany(Baz, { sourceKey: 'title', foreignKey: 'barTitle' });
// [...]
await Bar.setFoo("Foo's Name Here");
await Baz.addBar("Bar's Title Here");

ref https://sequelize.org/master/manual/advanced-many-to-many.html#using-one-to-many-relationships-instead