作者:知晓云 - 小程序开发快人一步
来源:知晓课堂

在日常的工作中,常常需要根据运营需求对数据进行各种格式的处理和导出。导出后,不少人偏爱将数据放入 excel在进行处理。

一般来说,处理数据导出时需要对数据进行一些运算整理。在以前,处理的方式是在一台独立的服务器上跑脚本。

而现在有了知晓云,不再需要维护服务器,直接写代码就能把相关事都都丢给云函数。 本文将介绍通过知晓云云函数来实现将数据表导出为 excel 文件的功能,并使用 webpack 和 mincloud 将代码打包上传到知晓云。

技术栈:

  • 打包工具:webpack@4.22.0
  • 部署工具:mincloud@1.0.4
  • Excel 处理:node-xlsx@0.14.1
  • 其他:知晓云 SDK

一、项目搭建

项目文件结构:

export-excel-file
├── index.js
├── package.json
├── src
│ └── index.js
├── webpack.config.js
└── yarn.lock

项目搭建与云函数代码打包示例文档基本一致。项目搭建好后,还需要安装以下依赖(两种安装方式选其一即可):

// 使用 yarn 安装
yarn add node-xlsx mincloud
// 使用 npm 安装
npm install --save node-xlsx minclou `

修改 deploy 脚本,如下:

// package.json
...
"scripts": {   "build": "webpack --mode production",  "predeploy": "npm run build",  "deploy": "mincloud deploy export-excel-file ../"  },  ...

最终我们会使用以下两个命令来部署和测试:

npm run deploy  // 部署到知晓云
mincloud invoke export-excel-file  // 测试已经部署到知晓云上的云函数

二、将数据表导出为 excel 文件

我们需要准备两张表:

  • order: 订单表 (新建字段:name, price)
  • export_task:导出任务记录表 (新建字段:file_download_link)

知晓云的云函数调用有同步和异步两种方式,同步调用的最大超时时间为 5 s,异步调用的则为 300 s。

假定 order 订单表有十万条数据,由于知晓云单次拉取数据的最大限制为 1000 条,所以需要分批获取数据,加上后续可能需要对数据进行处理,所花费的时间将会超过 5 s,因此对该云函数的调用将采用异步的方式。这时候就需要 export_task 导出任务记录表来对导出任务进行管理了。

export_task 表对导出任务进行管理的流程如下:

  1. 调用云函数时在 export_task 表中创建一条记录 A,此时记录 A 中的 file_download_link 字段值为空,同时拿到记录 A 的 id,记这个 id 为 jobId

  2. 进行 order 表数据查询,excel 文件生成,文件上传等操作,拿到文件下载链接

  3. 之后根据 jobId 来更新第一步创建的记录,保存文件下载链接到 file_download_link 字段中

  4. 更新完后就能在 export_task 表中拿到文件下载链接

通过上面的准备和分析,对导出 excel 文件操作分为以下 4 个步骤:

  1. order 订单表数据获取

  2. 使用获取的数据在云函数环境下创建 excel 文件

  3. 将创建出的 excel 文件上传到知晓云

  4. 保存文件下载链接到 export_task 表中的 file_download_link 字段

完整代码如下:

const fs = require('fs')
const xlsx = require('node-xlsx')const EXPORT_DATA_CATEGORY_ID = '5c711e3119111409cdabe6f2'    // 文件上传分类 id
const TABLE_ID = {order: 66666,         // 订单表export_task: 66667,   // 导出任务记录表
}const TMP_FILE_NAME = '/tmp/result.xlsx'  // 本地临时文件路径,以 /tmp 开头,具体请查看:https://doc.minapp.com/support/technical-notes.html (云函数的临时文件存储)
const ROW_NAME = ['name', 'price']        // Excel 文件列名配置
const MAX_CONNECT_LIMIT = 5               // 最大同时请求数
const LIMIT = 1000                        // 单次最大拉取数据数
let result = []/*** 更新导出记录中的 file_download_link 字段* @param {*} tableID * @param {*} recordId * @param {*} fileLink */
function updateExportJobIdRecord(tableID, recordId, fileLink) {let Schame = new BaaS.TableObject(tableID)let schame = Schame.getWithoutData(recordId)schame.set('file_download_link', fileLink)return schame.update()
}/*** 创建数据导出任务* 设置初始 file_download_link 为空* 待导出任务执行完毕后将文件下载地址存储到 file_download_link 字段中* @param {*} tableID */
function createExportJobIdRecord(tableID) {let Schame = new BaaS.TableObject(tableID)let schame = Schame.create()return schame.set({file_download_link: ''}).save().then(res => {return res.data.id})
}/*** 获取总数据条数* @tableId {*} tableId*/
function getTotalCount(tableId) {const Order = new BaaS.TableObject(tableId)return Order.count().then(num => {console.log('数据总条数:', num)return num}).catch(err => {console.log('获取数据总条数失败:', err)throw new Error(err)})
}/*** 分批拉取数据* @param {*} tableId * @param {*} offset * @param {*} limit */
function getDataByGroup(tableId, offset = 0, limit = LIMIT) {let Order = new BaaS.TableObject(tableId)return Order.limit(limit).offset(offset).find().then(res => {return res.data.objects}).catch(err => {console.log('获取分组数据失败:', err)throw new Error(err)})
}/*** 创建 Excel 导出文件* @param {*} sourceData 源数据*/
function genExportFile(sourceData = []) {const resultArr = []const rowArr = []// 配置列名rowArr.push(ROW_NAME)sourceData.forEach(v => {rowArr.push(ROW_NAME.map(k => v[k]))})resultArr[0] = {data: rowArr,name: 'sheet1',    // Excel 工作表名}const option = {'!cols': [{wch: 10}, {wch: 20}]}    // 自定义列宽度const buffer = xlsx.build(resultArr, option)return fs.writeFile(TMP_FILE_NAME, buffer, err => {if (err) {console.log('创建 Excel 导出文件失败')throw new Error(err)}})
}/*** 上传文件*/
function uploadFile() {let MyFile = new BaaS.File()return MyFile.upload(TMP_FILE_NAME, {category_id: EXPORT_DATA_CATEGORY_ID}).catch(err => {console.log('上传文件失败')throw new Error(err)})
}module.exports = async function(event, callback) {try {const date = new Date().getTime()const groupInfoArr = []const groupInfoSplitArr = []const [jobId, totalCount] = await Promise.all([createExportJobIdRecord(TABLE_ID.export_task), getTotalCount(TABLE_ID.order)])const groupSize = Math.ceil(totalCount / LIMIT) || 1for (let i = 0; i < groupSize; i++) {groupInfoArr.push({offset: i * LIMIT,limit: LIMIT,})}console.log('groupInfoArr:', groupInfoArr)const length = Math.ceil(groupInfoArr.length / MAX_CONNECT_LIMIT)for (let i = 0; i < length; i++) {groupInfoSplitArr.push(groupInfoArr.splice(0, MAX_CONNECT_LIMIT))}console.log('groupInfoSplitArr:', groupInfoSplitArr)const date0 = new Date().getTime()console.log('处理分组情况耗时:', date0 - date, 'ms')let num = 0// 分批获取数据const getSplitDataList = index => {return Promise.all(groupInfoSplitArr[index].map(v => {return getDataByGroup(TABLE_ID.order, v.offset, v.limit)})).then(res => {++numresult.push(...Array.prototype.concat(...res))if (num < groupInfoSplitArr.length) {return getSplitDataList(num)} else {return result}})}Promise.all([getSplitDataList(num)]).then(res => {const date1 = new Date().getTime()console.log('结果条数:', result.length)console.log('分组拉取数据次数:', num)console.log('拉取数据耗时:', date1 - date0, 'ms')genExportFile(result)const date2 = new Date().getTime()console.log('处理数据耗时:', date2 - date1, 'ms')uploadFile().then(res => {const fileLink = res.data.file_linkconst date3 = new Date().getTime()console.log('上传文件耗时:', date3 - date2, 'ms')console.log('总耗时:', date3 - date, 'ms')updateExportJobIdRecord(TABLE_ID.export_task, jobId, fileLink).then(() => {const date4 = new Date().getTime()console.log('保存文件下载地址耗时:', date4 - date3, 'ms')console.log('总耗时:', date4 - date, 'ms')callback(null, {message: '保存文件下载地址成功',fileLink,})}).catch(err => {callback(err)})}).catch(err => {console.log('上传文件失败:', err)throw new Error(err)})})} catch (err)

三、部署并测试

跟 npm 一样,部署前需要先登录,请参照文档配置。

使用以下命令即可将云函数部署到知晓云:

 run deploy

执行结果如下:

使用以下的命令来测试:

mincloud invoke export-excel-filebr

执行结果如下:

export_task 表记录:

上传到知晓云的 excel 文件如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8xgPW2iK-1588065248145)(https://cloud-minapp-11491.cloud.ifanrusercontent.com/1h3eeGNECR14zCdk.png)]

文件内容:

四、参考文档

知晓云开发文档:https://doc.minapp.com/

node-xlsx 文档:https://www.npmjs.com/package/node-xlsx

五、源码

仓库地址:https://github.com/ifanrx/export-excel-file

相关阅读

第一期:快速实现图片爬虫
第二期:快速生成分享海报
第三期:处理微信卡券消息
第四期:自动回复客服消息
第五期:生成带参数的二维码

关注「知晓云」公众号,点击菜单栏「知晓云」-「知晓课堂」,获取更多开发教程。

第六期:如何通过知晓云将数据表导出为 Excel 文件相关推荐

  1. 微信小程序-知晓云等云产品导出excel

    参考链接:微信小程序通过知晓云云函数导出excle(无须后台开发)_流转往复的博客-CSDN博客 我是参考这篇文章做的,可以实现导出静态的excle,如果有更多的需求可以在此基础上自行拓展. 前言 我 ...

  2. ipv4v6双栈技术_【第二十六期】IPv6系列应用篇——数据中心IPv4/IPv6双栈架构探讨...

    背景 2017年,工业和信息化部发布了<推进互联网协议第六版(IPv6)规模部署行动计划>的通知,从国家层面推动下一代IP技术--IPv6的普及和应用.目标到2020年末,IPv6活跃用户 ...

  3. 第十六期:简单的介绍一下大数据中最重要的MapReduce

    MapReduce是分布式运行的,由两个阶段组成:Map和Reduce,Map阶段是一个独立的程序,有很多个节点同时运行,每个节点处理一部分数据. MapReduce执行流程图 概述 MapReduc ...

  4. 第三期:如何通过知晓云处理微信卡券消息

    作者:知晓云 - 小程序开发快人一步 来源:知晓课堂 知晓云新推出「消息推送」功能,该功能通过「消息推送」类型的触发器接收微信推送过来的消息,开发者可以对此消息实行相关操作. 此教程将带领大家体验这个 ...

  5. 微信小程序开发(以知晓云SDK作为后端)

    本篇介绍知晓云SDK开发需要注意的地方. 目录 一.知晓云配置 二.微信开发者工具中配置知晓云插件 三.连接数据库 四.通过链接访问知晓云数据库中文件资源 4.3 在微信公众平台中配置知晓云数据库域名 ...

  6. 第16期高级转录组分析和R数据可视化培训(2022年1月)

    福利公告:为了响应学员的学习需求,经过易生信培训团队的讨论筹备,现安排<高级转录组分析和R数据可视化>于2022年1月14-16 线上/线下课程 (线上课是通过腾讯会议实时直播线下课,实时 ...

  7. 【知云】第六期:数据级异地容灾如何实现?阿里云帮你打通数据的“任督二脉”...

    摘要:国家要求网络借贷信息中介机构成立两年内,应当建立或使用与其业务规模相匹配的应用级灾备设施.那么如何规划容灾设施呢?本文中阿里云架构师半农将与大家分享阿里云异地容灾解决方案. 想要看视频版?请点击 ...

  8. 第四期:如何通过知晓云自动回复客服消息

    作者:知晓云 - 小程序开发快人一步 来源:知晓课堂 在上篇推送完「卡券核销消息推送」的教程后,我们决定再多出点教程. 此次教程将再次带领大家体验「消息推送」,实现另一个「微信消息推送」的触发器,关于 ...

  9. 【第六期】拿不到offer全额退款 人工智能工程师培养计划招生

    前 言 学院第四期课程在2019年10月结课,第一至第四期具有求职意向的同学中,目前已经有80%的同学拿到了国内外名企的AI算法岗位offer,或者国外名校的AI 硕士.全奖博士录取 offer.在大 ...

最新文章

  1. RHEL 5服务篇—使用Apache搭建web服务(四)部署AWStats网站分析系统
  2. 将选择元素绑定到Angular中的对象
  3. Emacs基础命令整理 - Unplugged - 博客频道 - CSDN.NET
  4. Scala隐式参数(隐式值)
  5. linux u盘新建文件夹加密,linux磁盘的加密保护以及u盘加密的方法。
  6. 【网络】几种常见的协议
  7. 函数指针以及在类成员函数中应用函数指针
  8. c语言贪吃蛇(简易版本含完整代码)
  9. HackerRank Word Order
  10. 如何提高FPGA的工作频率
  11. rfm模型python_Python pandas RFM模型应用实例详解
  12. Julia文件和文件夹相关基础函数01
  13. HAKE笔记:Learning Hierarchy-Aware Knowledge Graph Embeddings for Link Prediction
  14. HBase的数据模型和存储原理
  15. “没用”的StringBuffer,StringBuffer被StringBuilder取代的原因
  16. AD——PCB布线实用技巧
  17. 选购kvm需要注意的重要事项
  18. 使用Maven WAR插件实现多Web应用间的重迭运用
  19. 《离散数学》学习笔记
  20. MATLAB编写遗传算法求解vrp问题

热门文章

  1. 瀚龙广告提供一站式的新型广告模式!大大增加用户体验
  2. 邮箱密码忘了怎么找回?电子邮箱密码怎么改和填写?
  3. 服装企业在实践中探索
  4. 计算机二级知识点——栈
  5. 通过proj4js实现不同椭球之间的坐标点的七参数转换
  6. osgEarth的Rex引擎原理分析(二十五)地形瓦片大小尺寸和LOD的关系
  7. Ajax的网络响应时间
  8. 高数_第6章无穷级数
  9. win、linux环境下JAVA+GDAL部署,jar包启动,相关描述,问题解决
  10. python利器官网-python利器app