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

AppScript生成JSON插入PostgreSQL失败:Node.js代码故障排查

问题排查:Node.js无法将AppScript生成的JSON插入PostgreSQL

我编写的Node.js代码无法将AppScript生成的JSON数据插入PostgreSQL数据库。单独打印JSON显示正常,数据库连接也能正常查询已有数据,但数据始终无法入库。已核对字段名与数据类型,仍未找到问题所在,相关代码如下:

const { Client } = require('pg');
const fetch = require('node-fetch').default;

const obtenerItinera = async () => {
  const client = new Client({
    user: 'postgres',
    host: 'localhost',
    database: 'pruebas',
    password: '123456',
    port: 5432,
  });

  await client.connect();

  const res = await client.query('SELECT * FROM datos_generales');
  const result = res.rows;

  await client.end();

  return result;
};

const insertarDatos = async (data) => {
  const client = new Client({
    user: 'postgres',
    host: 'localhost',
    database: 'pruebas',
    password: '123456',
    port: 5432,
  });

  await client.connect();

  for (let i = 0; i < data.length; i++) {
    const row = data[i];

    // Verificar si la fila ya existe en la base de datos por su valor de vuelo
    try {
      const res = await client.query('SELECT COUNT(*) FROM datos_generales WHERE vuelo = $1', [row.vuelo]);
      const count = parseInt(res.rows[0].count);

      if (count === 0) {
        // La fila no existe en la base de datos, realizar la inserción
        console.log('Insertando fila:', row);

        await client.query(`INSERT INTO datos_generales (vuelo, eta, etd, ata, atd) VALUES ($1, $2, $3, $4, $5)`, [row.vuelo, row.eta, row.etd, row.ata, row.atd]);
        console.log('Fila insertada:', row);
      } else {
        console.log('La fila ya existe en la base de datos, omitiendo inserción:', row);
      }
    } catch (error) {
      console.error('Error al realizar la inserción:', error);
    }
  }

  const res = await client.query('SELECT * FROM datos_generales');
  const result = res.rows;

  await client.end();

  return result;
};

async function downloadJSON() {
// el link fue cortado
  const url = 'https://script.google.com/macros/s/exec'; // Reemplaza con la URL real tu API

  try {
    const response = await fetch(url);
    const data = await response.json();

    // Insertar los datos en la base de datos
    const resultadoInsercion = await insertarDatos(data);
    console.log('Datos insertados:', resultadoInsercion);

    // Realizar la consulta SELECT * después de agregar los datos
    const resultadoConsulta = await obtenerItinera();
    console.log('Datos obtenidos:', resultadoConsulta);
  } catch (error) {
    console.error('Error al descargar el JSON o insertar los datos:', error);
  }

  // Programar la próxima descarga después de 5 segundos
  setTimeout(downloadJSON, 5000);
}

// Iniciar la descarga inicial
downloadJSON();

排查方向与修复建议

1. 增强错误日志定位问题

当前insertarDatos函数的catch块仅打印错误信息,无法关联到具体出错的行数据。修改catch块,补充打印当前处理的行内容,方便定位具体哪条数据出问题:

catch (error) {
  console.error('Error al insertar fila:', row, '\nDetalles:', error);
}

2. 校验字段名与数据类型的隐性不匹配

  • 确认AppScript返回的JSON字段名大小写完全匹配数据库字段:比如数据库是vuelo,JSON里不能是Vuelo或VUELO;
  • 检查日期字段(eta/etd/ata/atd)的格式:PostgreSQL的timestamp/timestamptz类型要求严格的日期格式(如YYYY-MM-DD HH:MI:SS或ISO格式YYYY-MM-DDTHH:MI:SSZ),如果AppScript返回的是其他格式(如DD/MM/YYYY),需要手动转换:
    // 示例:将字符串日期转换为ISO格式
    const formatDate = (dateStr) => {
      if (!dateStr) return null;
      return new Date(dateStr).toISOString();
    };
    
    // 插入时替换日期字段
    await client.query(
      `INSERT INTO datos_generales (vuelo, eta, etd, ata, atd) VALUES ($1, $2, $3, $4, $5)`,
      [row.vuelo, formatDate(row.eta), formatDate(row.etd), formatDate(row.ata), formatDate(row.atd)]
    );
    

3. 修复重复检查逻辑的潜在问题

  • 如果vuelo字段可能为null或空字符串,COUNT(*)的判断会失效(因为NULL = NULL在SQL中不成立),修改查询语句:
    const res = await client.query(`
      SELECT COUNT(*) FROM datos_generales 
      WHERE (vuelo = $1 OR (vuelo IS NULL AND $1 IS NULL))
    `, [row.vuelo]);
    
  • 确认vuelo字段的数据类型完全匹配:比如数据库是INT类型,JSON返回的row.vuelo不能是字符串类型(需转换为数字:parseInt(row.vuelo))。

4. 验证插入语句的执行结果

可以通过client.query的返回结果确认插入是否成功,比如打印受影响的行数:

const insertRes = await client.query(
  `INSERT INTO datos_generales (vuelo, eta, etd, ata, atd) VALUES ($1, $2, $3, $4, $5)`,
  [row.vuelo, row.eta, row.etd, row.ata, row.atd]
);
console.log('Fila insertada, filas afectadas:', insertRes.rowCount);

5. 优化数据库连接复用

当前每次调用obtenerItinera和insertarDatos都新建连接,建议复用单个客户端连接,减少资源消耗:

// 全局创建客户端连接
const client = new Client({
  user: 'postgres',
  host: 'localhost',
  database: 'pruebas',
  password: '123456',
  port: 5432,
});

// 初始化连接
async function initDB() {
  await client.connect();
  console.log('Conectado a PostgreSQL');
}

// 修改obtenerItinera,不再创建新连接
const obtenerItinera = async () => {
  const res = await client.query('SELECT * FROM datos_generales');
  return res.rows;
};

// insertarDatos同理,去掉新建client的代码,直接用全局client

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:37:42