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

Sequelize批量插入SQLite仅6k条,137k条API数据丢失求助

问题:137k条数据仅插入6k到SQLite,导出文本却完整

我通过多轮API调用获取了137k条数据,计划写入SQLite数据库,但最终仅成功插入约6k条记录;不过将数据导出到文本文件时,能得到完整的137k条内容。以下是我的数据库插入相关代码:

index.js

const db = require("./config/database");
const items = require("./models/items");
var fs = require('fs');
const baseURL = 'xxx';
const namespace = 'static-eu';
const region = 'eu';
const client = 'xxx';
const secret = 'xxx';
const tokenURL = 'xxx';

const getToken = async function(client, secret)
{
    const body = "grant_type=client_credentials";
    const response = await fetch(tokenURL, {
        method: 'post',
        body: body,
        headers: {'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Basic ' + Buffer.from(client + ':' + secret).toString('base64')}
    });
    const data = await response.json();
    const jsondata = JSON.stringify(data);
    const json = JSON.parse(jsondata);
    return json['access_token'];
}
const getItems = async function(ID)
{
    const access_token =  await getToken(client, secret);
    const reqURL = baseURL + '/data/wow/search/item?namespace=' + namespace + '&_pageSize=1000&orderby=id&id=['+ ID + ',]&access_token=' + access_token;
    const response = await fetch(reqURL, {
        method: 'get',
        //headers: {'Authorization': 'Bearer ' + access_token}
    });
    const data = await response.json();

    const jsondata = JSON.stringify(data);
    const json = JSON.parse(jsondata);
    var arrayID = [];
    json.results.forEach(function (item, index){
           try {
               items.upsert({
                   itemID: json.results[index].data.id,
                   desc_de: json.results[index].data.name.de_DE,
                   desc_en: json.results[index].data.name.en_US,
                   media: json.results[index].data.id,
                   item_class_de: json.results[index].data.item_class.name.de_DE,
                   item_class_en: json.results[index].data.item_class.name.en_US,
               });
           }
           catch (error) {
               return console.log(error.name + error.message);
           }
        arrayID.push(json.results[index].data.id);
        });

    const nextID = (Math.max(...arrayID)) + 1;
    return nextID;
}
const getAll = async function()
{
    let ID = 1;
    while(1==1)
    {
        console.log(ID);
        ID = await getItems(ID);
}};

db.authenticate()
    .then(() => {
        console.log('Logged in to DB!');
        items.init(db);
        items.sync();
    })
    .catch(err => console.log(err));
getAll();

items.js

const { DataTypes, Model } = require('sequelize');
module.exports = class items extends Model {
    static init(sequelize){
        return super.init({
            itemID: {
                type: DataTypes.INTEGER,
                allowNull: false,
                unique: true
            },
            desc_de: DataTypes.STRING,
            desc_en: DataTypes.STRING,
            media: DataTypes.INTEGER,
            item_class_de: DataTypes.STRING,
            item_class_en: DataTypes.STRING,
        }, {
            tableName: 'items',
            timestamps: true,
            sequelize
        });
    }
}

database.js

const { Sequelize } = require('sequelize');
module.exports = new Sequelize('database', 'user', 'password', {
    host: 'localhost',
    dialect: 'sqlite',
    logging: false,
    storage: './data/items.sqlite',
});

问题原因及解决方案

核心问题

  1. 异步操作未等待:items.upsert()是异步Promise,但forEach循环不会等待它完成,导致大量插入操作被“丢弃”,还没执行就进入下一轮循环。
  2. 错误处理中断循环:catch里的return会直接终止整个forEach,一旦某条数据插入出错,后续所有数据都不会处理。
  3. 表同步未完成就插入:items.sync()是异步操作,还没创建好表就开始插入,导致部分插入失败。
  4. 重复请求Token:每次getItems都调用getToken,频繁请求可能触发API限流,间接导致数据获取或插入中断。

解决方案

1. 替换forEach为for...of,等待每个插入完成

把json.results.forEach改成for...of循环,用await等待upsert完成,确保每条数据都被处理:

// 替换原forEach部分
var arrayID = [];
for (const item of json.results) {
  try {
    await items.upsert({
      itemID: item.data.id,
      desc_de: item.data.name.de_DE,
      desc_en: item.data.name.en_US,
      media: item.data.id,
      item_class_de: item.data.item_class.name.de_DE,
      item_class_en: item.data.item_class.name.en_US,
    });
    arrayID.push(item.data.id);
  } catch (error) {
    console.error(`插入ID ${item.data.id}失败:`, error.message);
    // 去掉return,继续处理下一条数据
  }
}

2. 缓存Token,避免重复请求

Token一般有有效期,缓存起来不用每次请求都获取:

let cachedToken = null;
let tokenExpiry = 0; // 过期时间戳

const getToken = async function(client, secret) {
  const now = Date.now();
  // 如果缓存Token未过期,直接返回
  if (cachedToken && now < tokenExpiry) {
    return cachedToken;
  }
  const body = "grant_type=client_credentials";
  const response = await fetch(tokenURL, {
    method: 'post',
    body: body,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic ' + Buffer.from(client + ':' + secret).toString('base64')
    }
  });
  const data = await response.json();
  cachedToken = data.access_token;
  // 用API返回的expires_in设置过期时间,默认3600秒
  tokenExpiry = now + (data.expires_in || 3600) * 1000;
  return cachedToken;
}

3. 等待表同步完成再启动插入

在db.authenticate()的回调里,等待items.sync()完成后再调用getAll():

db.authenticate()
  .then(async () => {
    console.log('已连接到数据库!');
    items.init(db);
    await items.sync(); // 等待表创建/同步完成
    await getAll(); // 再启动数据插入
  })
  .catch(err => console.log(err));
// 删掉原来单独调用的getAll()

4. 批量插入优化(可选,大幅提升效率)

对于大量数据,用bulkCreate配合updateOnDuplicate实现批量upsert,比单条插入快得多:

// 在getItems里,先收集所有数据,再批量插入
const itemsToUpsert = json.results.map(item => ({
  itemID: item.data.id,
  desc_de: item.data.name.de_DE,
  desc_en: item.data.name.en_US,
  media: item.data.id,
  item_class_de: item.data.item_class.name.de_DE,
  item_class_en: item.data.item_class.name.en_US,
}));

try {
  await items.bulkCreate(itemsToUpsert, {
    updateOnDuplicate: ['desc_de', 'desc_en', 'media', 'item_class_de', 'item_class_en']
  });
  // 收集ID
  arrayID.push(...itemsToUpsert.map(item => item.itemID));
} catch (error) {
  console.error('批量插入失败:', error.message);
}

内容的提问来源于stack exchange,提问作者Christoph Ritzer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:39:35