创建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}`));
四、测试与定时触发
- 本地测试:启动服务后用CURL触发
curl http://localhost:3000/schedule
- 服务器定时触发:编辑Cron任务,比如每天凌晨3点执行
crontab -e # 添加以下内容(根据你的Node路径和服务地址调整) 0 3 * * * curl http://localhost:3000/schedule
关键优化点
- 用
bulkWrite批量操作替代循环单条存库,提升效率 upsert逻辑避免重复数据,同时支持更新已有数据- 捕获特定错误(如重复索引),确保流程不中断
内容的提问来源于stack exchange,提问作者Mike Tower
相关产品推荐
相关产品推荐

