在平常的工做中,經常須要根據運營需求對數據進行各類格式的處理和導出。導出後,很多人偏心將數據放入 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...
知曉雲是國內首家專一於小程序開發的後端雲服務。使用知曉雲,小程序開發快人一步。