nodejs + mongo + redis + oss追加写入CSV文件-程序员宅基地

技术标签: node.js  mongodb  redis  javascript  

const fs = require(‘fs’);
const path = require(‘path’);
const ENUM = require(‘…/…/extend/enum’);
const OSS = require(‘ali-oss’);
const page = 1;
const limit = 1000;
let OSS_CONFIG = think.config(‘OSS_CONFIG’)
OSS_CONFIG[‘timeout’] = 86400

module.exports = class extends think.Controller {
async writeSvc(data){
const object_id = data._id
if (think.isEmpty(OSS_CONFIG) || !object_id) {
await this.editDataSvc(object_id, {status: 4, fail_reason: ${object_id}未找到oss配置})
return
}
let params = data.where || {}
params.limit = limit;
params.page = page;
// 构建查询参数
const channel = data.channel;
const menu_button = data.menu_button || []
// 下载类型
let downloadType = data.downloadType;

let result = {};
// 构建开始 ---------------------------------------------------------------------
// 去除参数中为空字符串的条件
params = Object.fromEntries(
  Object.entries(params).filter(([key, value]) => value !== "")
);
// 根据下载类型调用相应的导出方法
switch (downloadType) {
    case "userList":
        result = await think.model("common/derive").userListExport(params, channel, menu_button);
        break;
    case "ExchangeList":
        result = await think.model("common/derive").GetWithdrawListExport(params, channel);
        break;
    case "payRecord":
        result = await think.model("common/derive").GetPayRecordExport(params, channel);
        break;
    case "DrawInfoRecord":
        result = await think.model("common/derive").getDrawPageRecordExport(params, channel);
        break;
    case "gameData":
        result = await think.model("common/derive").getGameStaticsDataExport(params, channel);
        break;
    case "ActiveDetails":
        result = await think.model("common/derive").ActiveDetails(params, channel);
        break;
    default:
        console.log("无效的下载类型");
}
// 构建结束 ---------------------------------------------------------------------
// 此次下载总数量
const total = result.count

console.log(`导出类型:${downloadType},导出数量:${total}`);

// 数量检查
if (total >= 1000000 || think.isEmpty(total)) {
  await this.editDataSvc(object_id, {status: 4, fail_reason: '导出数据超过限制或无数据'})
  console.log('导出数据超过限制');
  return;
}

// 记录总次数
await this.editDataSvc(object_id, {export_quantity: total})

const numOfIterations = Math.ceil(total / limit); // 计算需要循环导出的次数
console.log(`应循环总次数为 ${numOfIterations}`);

// 定义文件夹名称
const folderName = 'downloadCenter';
// 确定文件夹路径
const folderPath = path.join(think.ROOT_PATH, folderName);

// 如果文件夹不存在,则创建文件夹
if (!fs.existsSync(folderPath)) {
  fs.mkdirSync(folderPath);
}

// 定义CSV文件名称
const csvFileName = path.join(folderPath, `${Date.now()}_${think.uuid()}.csv`);

// 如果文件不存在,则写入BOM和表头
if (!fs.existsSync(csvFileName)) {
  const bom = Buffer.from("EFBBBF", "hex").toString("utf-8");
  const headers = Object.values(data.ToCnName); // 获取表头的中文列名
  fs.writeFileSync(csvFileName, bom + headers.join(',') + '\n');
}

// 支付方式枚举
const pay_payment = await think.mongoPay('conf_pay_type').field('_id, remarks').select();
// 跳转位置
const jumpList = await think.mongoConf('conf_jump_enums').field('value, name').select();
//获取支付平台
const paymentPlatform = await think.mongoPay('conf_channel').select();

// 进度
let downloadedBytes = 0;
// 循环导出数据
for (let i = 0; i < numOfIterations; i++) {
  console.log(data.file_name + '循环次数·', i + 1);
  // 下载页码
  params.page = i + 1;
  // 下载数据
  let list = {};
  switch (downloadType) {
    case "userList":
        let userList = await think.model("common/derive").userListExport(params, channel, menu_button);
        list = await ENUM.usersDataReplace(userList.data)
        break;
    case "ExchangeList":
        let withdrawList = await think.model("common/derive").GetWithdrawListExport(params, channel);
        list = await ENUM.getExchangeData(withdrawList.data, params, paymentPlatform)
        break;
    case "payRecord":
        let payRecordList = await think.model("common/derive").GetPayRecordExport(params, channel);
        list = await ENUM.getPayRecordData(payRecordList.data, params, pay_payment, jumpList, paymentPlatform)
        break;
    case "DrawInfoRecord":
        let DrawInfoRecordList = await think.model("common/derive").getDrawPageRecordExport(params, channel);
        list = await ENUM.getDrawInfoRecordData(DrawInfoRecordList.data)
        break;
    case "gameData":
        let gameDataList = await think.model("common/derive").getGameStaticsDataExport(params, channel);
        list = await ENUM.getGameData(gameDataList.data,  params.game_enum)
        break;
    default:
        console.log("无效的下载类型");
  }
  // 追加写入数据
  for (const record of list) {
    const rowValues = Object.keys(data.ToCnName).map(key => {
      let value = record[key];
      if (typeof value !== 'string') {
        value = String(value); // 将非字符串类型的值转换为字符串
      }
      // 如果数据中包含逗号,则用双引号括起来
      return value.includes(',') ? `"${value}"` : value;
    });
    fs.appendFileSync(csvFileName, rowValues.join(',') + '\n');
  }
  downloadedBytes += list.length;
  const progress = Math.floor((downloadedBytes / total) * 100);
  await this.editDataSvc(object_id, {progress: progress})
}
// 上传oss
// 定义CSV文件路径  
const csvFilePath = `${folderName}/${think.formatDate(Date.now(), 'yyyy-MM-dd')}/${data.file_name}.csv`;
let url = await this.upOssloadFile(object_id, csvFilePath, csvFileName)
if (url) {
  // 删除文件
  fs.unlink(csvFileName, (err) => {
    if (err) {
      console.error('Error deleting file:', err);
      return;
    }
    console.log('File deleted successfully');
  });
  await this.editDataSvc(object_id, {status: 2, download_url: url})
} else {
  await this.editDataSvc(object_id, {status: 4, fail_reason: 'oss上传失败'})
}
console.log('CSV 文件写入完成');

}

// 上传文件
async upOssloadFile(object_id, csvFilePath, csvFileName) {
const ossClient = new OSS(OSS_CONFIG);
try {
await this.editDataSvc(object_id, {status: 5})
const result = await ossClient.put(csvFilePath, csvFileName);
let url = await this.extractPathAfterDomain(result[‘url’])
return url
} catch (err) {
console.error(‘Upload error:’, err);
}
}

async extractPathAfterDomain(url) {
// 匹配域名后的路径
var pathAfterDomain = url.match(/(?:https?/)?(?:[@\n]+@)?(?:www.)?[\n?]+(/[^?#]+)/img);
if (pathAfterDomain && pathAfterDomain.length > 0) {
// 返回匹配的路径
return pathAfterDomain[0].replace(/.*//[/]+/, ‘’);
} else {
return null;
}
}

// 更新下载进度及其他信息
async editDataSvc(id, data) {
await think.mongoRecord(‘record_download_csv_list’).where({_id: id}).update({$set: data})
}
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_32531777/article/details/137671137

智能推荐

Win cuda11+cudnn11网盘下载_win11 cudatookit安装包 百度云-程序员宅基地

文章浏览阅读5.1k次,点赞17次,收藏10次。https://pan.baidu.com/s/1IV_lBCeFFM712xx_iXnhqQ 提取码:0pr5_win11 cudatookit安装包 百度云

springboot集成thymeleaf时css js加载不出来的问题_springboot thymeleaf 不显示css js-程序员宅基地

文章浏览阅读2.1k次。springboot项目的css 和js默认位置是在static中,所以如果没有另外的修改的话,直接创建一个static文件夹,把css和js放入即可。这里放一个实例<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>儿童随访记录表</title> <!-- 引入 echarts.js --> <script src="ht._springboot thymeleaf 不显示css js

用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力_chatgpt + ai 数字人 csdn-程序员宅基地

文章浏览阅读2.1k次。这里还可以选择背景编辑以更换背景,虚拟人物的位置可以调整,都设置完成后,点击播放按钮,即可播放效果。(ps:未导出视频之前,数字人只是静态。)最后点击’合成’按钮,导出视频。_chatgpt + ai 数字人 csdn

C++编程法则365天一天一条(214)C++函数的默认参数详解_c++函数默认值在参数列表中在后面还是在前面-程序员宅基地

文章浏览阅读1.6w次。默认参数并非编程方面的重大突破,而只是提供了一种便捷的方式。在以后设计类时你将发现,通过使用默认参数,可以减少要定义的析构函数、方法以及方法重载的数量。_c++函数默认值在参数列表中在后面还是在前面

Android 自定义软键盘实现 数字九宫格_android studio九宫格软键盘设置-程序员宅基地

文章浏览阅读744次。前言最近项目在对接美团外卖功能 实现外面小哥凭取货码取货对接完功能后 用户反馈 弹出的软键盘 很难输入 数字太小了大概是下面这种显示方式需求组长说 要不搞一个自定义软键盘吧 数字搞大点 方便外卖员输入数字我设置了输入EditText的输入格式为Number 还是不行那就开搞吧先来看下实现的效果图吧实现效果GIF实现代码自定义View 一个NineNumericKeyboardView/** * Author by Lyu * Date on 2021/5/26-19:55 _android studio九宫格软键盘设置

从0开始用python实现神经网络 IMPLEMENTING A NEURAL NETWORK FROM SCRATCH IN PYTHON – AN INTRODUCTION...-程序员宅基地

文章浏览阅读150次。code地址:https://github.com/dennybritz/nn-from-scratch文章地址:http://www.wildml.com/2015/09/implementing-a-neural-network-from-scratch/ Get the code: To follow along, all the code is also available as a..._nerual networks from stratch in python

随便推点

TensorFlow Serving模型转换与部署_tensorflow serving 切换模型-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏23次。文章目录1. TensorFlow Serving安装1.1. 拉取镜像1.2. 下载官方代码1.3. 运行TF Serving1.4. 客户端验证2. 将ckpt模型转换为pb模型3. 模型部署4. 多模型部署4.1 多(单)用户单模型4.2 多(单)用户多模型4.3. 接口请求5. 新增模型6. 可能出现的错误错误1:错误2:错误3:错误4:错误5:错误6:错误7:错误8TensorFlow..._tensorflow serving 切换模型

::after伪元素增加小箭头样式_::after箭头-程序员宅基地

文章浏览阅读453次。::after伪元素增加小箭头样式_::after箭头

python3 OpenCV cv2 图像的细化(骨架抽取)_图像处理作业_cv2.thin-程序员宅基地

文章浏览阅读1.9w次,点赞14次,收藏83次。参考链接:http://www.cnblogs.com/xianglan/archive/2011/01/01/1923779.html主思路和程序基本上都是参考博主的,只是在思路理解上和Python3的一些小修改.首先是算法原理介绍:图像细化:图像细化主要是针对二值图而言,所谓骨架,可以理解为图像的中轴,,一个长方形的骨架,是它的长方向上的中轴线,圆的骨架是它的圆心,直线的骨架是它自身,孤立点的..._cv2.thin

解决microsoft visual c++ build tools安装包丢失或损坏_microsoft visual c++ build tool离线安装包-程序员宅基地

文章浏览阅读2w次,点赞6次,收藏10次。一.问题背景Windows需要在安装某些库的时候需要自己编译,但如果本机没有对应的编译的环境,就会产生如下报错: Building wheel for fasttext (setup.py) ... error ERROR: Command errored out with exit status 1: command: 'c:\users\jayce\anaconda3\envs\pdocr\python.exe' -u -c 'import io, os, sys, setupto_microsoft visual c++ build tool离线安装包

什么是架构以及架构的分类-程序员宅基地

文章浏览阅读1.8w次,点赞16次,收藏146次。写这篇文章的目的是弄明白到底什么是架构,我们在开发设计过程中会遇到各种各样的图,到底哪些是属于架构图?别人让你画架构图的时候,你要知道你画的到底是不是架构图,怎么画架构图。一、什么是架构把一个整体(完成人类生存的所有工作)切分成不同的部分(分工),由不同角色来完成这些分工,并通过建立不同部分相互沟通的机制,使得这些部分能够有机的结合为一个整体,并完成这个整体所需要的所有活动,这就是架构。边界划分:根据要解决的问题,对目标系统的边界进行界定。能力划分:对目标系统按某个原则的进行切分。切分的原则,要便_架构

C++ 每日一练---统计每个月兔子的总数(迭代法)_1238: 【入门】统计每个月兔子的总数-程序员宅基地

这篇文章介绍了使用C++迭代法统计每个月兔子的总数,通过给出兔子生长规律的例子,并使用代码实现了统计月兔子总数的方法。

推荐文章

热门文章

相关标签