You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Node.js与Sequelize实现SQL数据库数据插入与模型创建?

基于Sequelize创建模型并插入数据的方案

一、Sequelize模型优化方案

你的当前方案用JSON类型存储config和points是可行的,但如果后续需要对嵌套字段做查询、统计,更推荐拆分关联模型,以下两种方案供你选择:

方案1:保持JSON类型存储(快速实现)

你的现有模型可以直接用,但需要修正几个细节:

  • 移除不必要的hash排除字段(模型里没定义这个属性)
  • 给JSON字段加默认值,避免空值
const { DataTypes } = require('sequelize');

module.exports = model;
function model(sequelize) {
    const attributes = {
        config: {
            type: DataTypes.JSON,
            allowNull: false,
            defaultValue: {} // 默认空对象
        },
        points: {
            type: DataTypes.JSON,
            allowNull: false,
            defaultValue: [] // 默认空数组
        },
        // 单独存储user_id,方便后续按用户查询数据
        user_id: {
            type: DataTypes.INTEGER,
            allowNull: false
        }
    };

    const options = {
        timestamps: true, // 自动添加createdAt、updatedAt字段,便于追踪数据
        tableName: 'interactive_images' // 自定义语义化表名
    };

    return sequelize.define('InteractiveImage', attributes, options);
}

方案2:拆分关联模型(适合复杂查询场景)

如果后续需要单独查询某个point、修改tooltip内容,拆分模型更合理,避免JSON字段的操作限制:

  1. 主模型:InteractiveImage(对应原config)
  2. 关联模型:Point(对应原points数组项)
  3. 关联模型:Tooltip(对应每个point的tooltip)

主模型:InteractiveImage.js

const { DataTypes } = require('sequelize');

module.exports = model;
function model(sequelize) {
    const attributes = {
        config_id: {
            type: DataTypes.STRING,
            allowNull: false,
            unique: true // 原config.id设为唯一键
        },
        user_id: {
            type: DataTypes.INTEGER,
            allowNull: false
        },
        imageurl: {
            type: DataTypes.STRING,
            allowNull: false
        },
        name: {
            type: DataTypes.STRING,
            allowNull: false
        },
        server: {
            type: DataTypes.STRING
        },
        size: {
            type: DataTypes.STRING
        },
        imageWidth: {
            type: DataTypes.STRING
        },
        imageHeight: {
            type: DataTypes.STRING
        },
        hide_logo: {
            type: DataTypes.TINYINT,
            defaultValue: 0
        },
        point_color: {
            type: DataTypes.STRING
        },
        pulse: {
            type: DataTypes.BOOLEAN,
            defaultValue: false
        }
    };

    const options = {
        timestamps: true,
        tableName: 'interactive_images'
    };

    const InteractiveImage = sequelize.define('InteractiveImage', attributes, options);
    
    // 建立关联:一个InteractiveImage对应多个Point
    InteractiveImage.associate = function(models) {
        InteractiveImage.hasMany(models.Point, {
            foreignKey: 'interactive_image_id',
            onDelete: 'CASCADE' // 删除主数据时自动删除关联的points
        });
    };

    return InteractiveImage;
}

Point模型:Point.js

const { DataTypes } = require('sequelize');

module.exports = model;
function model(sequelize) {
    const attributes = {
        pointId: {
            type: DataTypes.STRING,
            allowNull: false,
            unique: true
        },
        x: {
            type: DataTypes.FLOAT,
            allowNull: false
        },
        y: {
            type: DataTypes.FLOAT,
            allowNull: false
        }
    };

    const options = {
        timestamps: true,
        tableName: 'points'
    };

    const Point = sequelize.define('Point', attributes, options);
    
    // 建立关联:一个Point对应一个Tooltip,同时关联主模型
    Point.associate = function(models) {
        Point.hasOne(models.Tooltip, {
            foreignKey: 'point_id',
            onDelete: 'CASCADE'
        });
        Point.belongsTo(models.InteractiveImage, {
            foreignKey: 'interactive_image_id'
        });
    };

    return Point;
}

Tooltip模型:Tooltip.js

const { DataTypes } = require('sequelize');

module.exports = model;
function model(sequelize) {
    const attributes = {
        tooltipId: {
            type: DataTypes.STRING,
            allowNull: false,
            unique: true
        },
        title: {
            type: DataTypes.STRING,
            allowNull: false
        },
        price: {
            type: DataTypes.STRING
        },
        link: {
            type: DataTypes.STRING
        },
        tooltipThumbnailUrl: {
            type: DataTypes.STRING
        },
        right: {
            type: DataTypes.STRING
        },
        left: {
            type: DataTypes.STRING
        },
        top: {
            type: DataTypes.STRING
        }
    };

    const options = {
        timestamps: true,
        tableName: 'tooltips'
    };

    const Tooltip = sequelize.define('Tooltip', attributes, options);
    
    Tooltip.associate = function(models) {
        Tooltip.belongsTo(models.Point, {
            foreignKey: 'point_id'
        });
    };

    return Tooltip;
}

二、数据插入实现

场景1:使用JSON类型模型插入

假设你已初始化Sequelize实例并导入模型:

const { sequelize } = require('./path/to/sequelize-config');
const InteractiveImage = require('./models/InteractiveImage')(sequelize);

// 插入数据的异步函数
async function saveInteractiveData(dataToSave) {
    try {
        const newData = await InteractiveImage.create({
            user_id: dataToSave.config.user_id,
            config: dataToSave.config,
            points: dataToSave.points
        });
        console.log('数据插入成功:', newData.toJSON());
        return newData;
    } catch (error) {
        console.error('插入失败:', error);
        throw error;
    }
}

// 调用函数插入目标数据
saveInteractiveData(dataToSave);

场景2:使用关联模型插入

用事务保证数据一致性,避免部分插入成功的情况:

const { sequelize } = require('./path/to/sequelize-config');
const InteractiveImage = require('./models/InteractiveImage')(sequelize);
const Point = require('./models/Point')(sequelize);
const Tooltip = require('./models/Tooltip')(sequelize);

async function saveInteractiveDataWithRelations(dataToSave) {
    const transaction = await sequelize.transaction();
    try {
        // 1. 插入主模型数据
        const image = await InteractiveImage.create({
            config_id: dataToSave.config.id,
            user_id: dataToSave.config.user_id,
            imageurl: dataToSave.config.imageurl,
            name: dataToSave.config.name,
            server: dataToSave.config.server,
            size: dataToSave.config.size,
            imageWidth: dataToSave.config.imageWidth,
            imageHeight: dataToSave.config.imageHeight,
            hide_logo: dataToSave.config.hide_logo,
            point_color: dataToSave.config.point_color,
            pulse: dataToSave.config.pulse
        }, { transaction });

        // 2. 遍历points插入关联数据
        for (const pointData of dataToSave.points) {
            const point = await Point.create({
                pointId: pointData.pointId,
                x: pointData.x,
                y: pointData.y,
                interactive_image_id: image.id
            }, { transaction });

            // 3. 插入对应的tooltip
            await Tooltip.create({
                tooltipId: pointData.tooltip.toltipId,
                title: pointData.tooltip.title,
                price: pointData.tooltip.price,
                link: pointData.tooltip.link,
                tooltipThumbnailUrl: pointData.tooltip.tooltipThumbnailUrl,
                right: pointData.tooltip.right,
                left: pointData.tooltip.left,
                top: pointData.tooltip.top,
                point_id: point.id
            }, { transaction });
        }

        // 提交事务
        await transaction.commit();
        console.log('关联数据插入成功');
        return image;
    } catch (error) {
        // 回滚事务
        await transaction.rollback();
        console.error('关联数据插入失败:', error);
        throw error;
    }
}

// 调用函数插入目标数据
saveInteractiveDataWithRelations(dataToSave);

内容的提问来源于stack exchange,提问作者The Dead Man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 19:34:53