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

创建Express端点实现定时拉取API数据存入MongoDB遇阻

解决方案:Express定时数据拉取路由实现

一、先完善MongoDB Model(解决重复数据问题)

给Schema添加唯一索引,基于外部API返回的唯一标识字段(比如externalId),确保重复数据无法插入:

// models/DataEntry.js
const mongoose = require('mongoose');

const dataEntrySchema = new mongoose.Schema({
  externalId: { type: String, required: true, unique: true }, // 绑定外部API的唯一ID
  title: String,
  content: String,
  // 其他业务字段
  createdAt: { type: Date, default: Date.now }
});

// 创建唯一索引,强制去重
dataEntrySchema.index({ externalId: 1 }, { unique: true });

module.exports = mongoose.model('DataEntry', dataEntrySchema);

二、编写/schedule路由核心逻辑

在scheduleRoute.js中实现API请求、数据提取、批量存库(用upsert实现存在则更新,不存在则插入):

// routes/scheduleRoute.js
const express = require('express');
const router = express.Router();
const axios = require('axios');
const DataEntry = require('../models/DataEntry');

// 外部API地址
const EXTERNAL_API_URL = 'https://your-target-api.com/data';

// 提取响应字段的映射函数
const extractTargetFields = (apiRes) => {
  // 根据外部API返回结构调整,这里假设返回数组格式
  return apiRes.data.map(item => ({
    externalId: item.id.toString(),
    title: item.title,
    content: item.description
    // 其他需要的字段映射
  }));
};

// 批量处理数据入库
const batchSaveData = async (dataList) => {
  const operations = dataList.map(item => ({
    updateOne: {
      filter: { externalId: item.externalId },
      update: { $set: item },
      upsert: true // 核心:不存在就插入,存在就更新
    }
  }));

  try {
    const result = await DataEntry.bulkWrite(operations);
    return {
      added: result.upsertedCount,
      updated: result.modifiedCount
    };
  } catch (err) {
    // 捕获唯一索引冲突(重复数据),不中断流程
    if (err.code !== 11000) throw err;
    console.log('跳过已存在的重复数据');
    return { added: 0, updated: 0 };
  }
};

// 触发路由
router.get('/', async (req, res) => {
  try {
    // 1. 请求外部API
    const apiResponse = await axios.get(EXTERNAL_API_URL);
    // 2. 提取目标字段
    const processedData = extractTargetFields(apiResponse);
    // 3. 批量存入MongoDB
    const saveResult = await batchSaveData(processedData);

    res.status(200).json({
      success: true,
      msg: `同步完成:新增${saveResult.added}条,更新${saveResult.updated}条`
    });
  } catch (err) {
    console.error('同步失败:', err);
    res.status(500).json({
      success: false,
      msg: '数据同步失败',
      error: err.message
    });
  }
});

module.exports = router;

三、在app.js中挂载路由并确保DB连接

// app.js
const express = require('express');
const mongoose = require('mongoose');
const scheduleRoute = require('./routes/scheduleRoute');

const app = express();

// 连接MongoDB
mongoose.connect('mongodb://localhost:27017/your-db-name')
  .then(() => console.log('MongoDB连接成功'))
  .catch(err => console.error('MongoDB连接失败:', err));

// 挂载路由
app.use('/schedule', scheduleRoute);

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`服务运行在端口 ${PORT}`));

四、测试与定时触发

  1. 本地测试:启动服务后用CURL触发
curl http://localhost:3000/schedule
  1. 服务器定时触发:编辑Cron任务,比如每天凌晨3点执行
crontab -e
# 添加以下内容(根据你的Node路径和服务地址调整)
0 3 * * * curl http://localhost:3000/schedule

关键优化点

  • 用bulkWrite批量操作替代循环单条存库,提升效率
  • upsert逻辑避免重复数据,同时支持更新已有数据
  • 捕获特定错误(如重复索引),确保流程不中断

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:55:59