在平常的工做中,经常须要根据运营需求对数据进行各类格式的处理和导出。导出后,很多人偏心将数据放入 excel 在进行处理。html
通常来讲,处理数据导出时须要对数据进行一些运算整理。在之前,处理的方式是在一台独立的服务器上跑脚本。node
而如今有了知晓云,再也不须要维护服务器,直接写代码就能把相关事都都丢给云函数。 本文将介绍经过知晓云云函数来实现将数据表导出为 excel 文件的功能,并使用 webpack
和 mincloud
将代码打包上传到知晓云。webpack
技术栈:git
webpack@4.22.0
mincloud@1.0.4
node-xlsx@0.14.1
项目文件结构:github
export-excel-file ├── index.js ├── package.json ├── src │ └── index.js ├── webpack.config.js └── yarn.lock
项目搭建与云函数代码打包示例文档基本一致。项目搭建好后,还须要安装如下依赖(两种安装方式选其一便可):web
// 使用 yarn 安装 yarn add node-xlsx mincloud // 使用 npm 安装 npm install --save node-xlsx minclou
修改 deploy 脚本,以下:npm
// package.json ... "scripts": { "build": "webpack --mode production", "predeploy": "npm run build", "deploy": "mincloud deploy export-excel-file ../" }, ...
最终咱们会使用如下两个命令来部署和测试:json
npm run deploy // 部署到知晓云 mincloud invoke export-excel-file // 测试已经部署到知晓云上的云函数
咱们须要准备两张表:
order: 订单表 (新建字段:name, price)
export_task:导出任务记录表 (新建字段:file_download_link) 小程序
知晓云的云函数调用有同步和异步两种方式,同步调用的最大超时时间为 5 s,异步调用的则为 300 s。segmentfault
假定 order
订单表有十万条数据,因为知晓云单次拉取数据的最大限制为 1000 条,因此须要分批获取数据,加上后续可能须要对数据进行处理,所花费的时间将会超过 5 s,所以对该云函数的调用将采用异步的方式。这时候就须要 export_task
导出任务记录表来对导出任务进行管理了。
export_task
表对导出任务进行管理的流程以下:
export_task
表中建立一条记录 A,此时记录 A 中的 file_download_link
字段值为空,同时拿到记录 A 的 id,记这个 id 为 jobId
order
表数据查询,excel 文件生成,文件上传等操做,拿到文件下载连接jobId
来更新第一步建立的记录,保存文件下载连接到 file_download_link
字段中export_task
表中拿到文件下载连接经过上面的准备和分析,对导出 excel 文件操做分为如下 4 个步骤:
order
订单表数据获取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) || 1 for (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 => { ++num result.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_link const 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
同样,部署前须要先登陆,请参照文档配置。
使用如下命令便可将云函数部署到知晓云:
npm run deploy
执行结果以下:
使用如下的命令来测试:
mincloud invoke export-excel-file
执行结果以下:
export_task
表记录:
上传到知晓云的 excel 文件以下:
文件内容:
知晓云开发文档:https://doc.minapp.com/node-xlsx
文档:https://www.npmjs.com/package...
仓库地址:https://github.com/ifanrx/exp...
即日( 3 月 8 日)起,前 50 名报名并经过审核的 Web 端公测的用户,在正式接入后即获帐户礼金 100 元。🎉
报名点这里 👉 知晓云公测活动 👈 除了这个好消息,小云还要告诉你们,公测活动结束后还将挑选出 5 名积极反馈的用户得到知晓云限量记念 T 恤呀
(。・ω・。)ノ♡
本文首发于「知晓云」公众号:https://mp.weixin.qq.com/s/g6...
知晓云是国内首家专一于小程序开发的后端云服务。使用知晓云,小程序开发快人一步。