Last active
February 5, 2020 06:31
-
-
Save bankchart/eee93bca45c7756f4f08f901da2f2383 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const moment = require('moment'); | |
| const _ = require('lodash'); | |
| const Excel = require('exceljs'); | |
| const striptags = require('striptags'); | |
| const backup = require('./backup_prod_2019-12-26.json'); | |
| const source = 'analytic_source.xlsm'; | |
| const fn = { | |
| cells: 0, | |
| updatedCells: 0, | |
| workbook: null, | |
| FARMER_ACCOUNT: '1', | |
| EXPERT_ACCOUNT: '2', | |
| TEMP_POST_FLAG: '0', | |
| PUBLIC_POST: '1', | |
| PRIVATE_POST: '2', | |
| IGNORE_ROWS_EXCEL: [1, 2], | |
| IGNORE_COLUMNS_EXCEL: [2, 3], | |
| COLUMNS_EXCEL_MAPPING_SHEET1: { | |
| deviceId: 1, | |
| displayName: 4, | |
| streamName: 5, | |
| nameSpaceId: 6, | |
| eventCount: 7, | |
| sessions: 8, | |
| revenue: 9, | |
| transactions: 10, | |
| conversions: 11, | |
| averageSessionDuration: 12, | |
| numberOfUniqeVisit: 13, | |
| numberOfLikePost: 14, //done | |
| numberOfLikeReply: 15, //done | |
| returningVisitFrequencyWeekly: 16, | |
| numberOfExpertConsultations: 17, //done | |
| numberOfAgronomistPost: 18, //done | |
| numberOfReadShareAgronomistPostComment: 19, | |
| numberOfLikeAgronomistPost: 20, //done | |
| numberOfLikeAgronomistComment: 21, //done | |
| bounceRate: 22, | |
| numberOfQuestionsPostedCommunityAndExperts: 23, //done | |
| numberOfReachedPosts: 24 | |
| }, | |
| COLUMNS_EXCELMAPPING_SHEET2: { | |
| postTopic: 1, | |
| userName: 2, | |
| postDate: 3, | |
| postTime: 4, | |
| tag: 5, | |
| detailOfPost: 6, | |
| farmersneedToKnowOtherCropsOrNot: 7, | |
| whatFarmerAskTopic: 8, | |
| numberOfRepeatedPostForEachUser: 9, | |
| leadTimeOfExpertToAnswerQuestion: 10 | |
| }, | |
| resetNumberCell: () => { | |
| fn.cells = 0, fn.updatedCells = 0; | |
| }, | |
| increaseUpdatedCell(val) { | |
| if(val > 0) { | |
| fn.updatedCells++; | |
| } | |
| }, | |
| updateCell: (row, columnIndex, val) => { | |
| row.getCell(columnIndex).value = val; | |
| fn.increaseUpdatedCell(val); | |
| fn.cells++; | |
| }, | |
| parseBodyPreview: (body) => { | |
| let bodyPreview = ''; | |
| let plainBody = striptags(body, [], ' '); | |
| plainBody = plainBody.trim().replace(/\s\s+/g, ' '); | |
| if (plainBody.length <= 100) { | |
| bodyPreview = plainBody | |
| } else { | |
| const words = plainBody.split(/\s+/) || []; | |
| let charCount = 0; | |
| const includedWords = []; | |
| for (let i = 0; i < words.length; i++) { | |
| if ((charCount + words[i].length) <= 100) { | |
| includedWords.push(words[i]); | |
| charCount += words[i].length + 1; | |
| } else { | |
| break; | |
| } | |
| } | |
| bodyPreview = includedWords.join(' '); | |
| } | |
| return bodyPreview; | |
| }, | |
| findNumberOfLike: (row, data, userId, fromDate, toDate) => { | |
| const columns = fn.COLUMNS_EXCEL_MAPPING_SHEET1; | |
| let numberOfLikePost = 0; | |
| let numberOfLikeReply = 0; | |
| let numberOfLikeAgronomistPost = 0; | |
| let numberOfLikeAgronomistComment = 0; | |
| for (let likeId of Object.keys(data.like)) { | |
| const inRangeDate = data.like[likeId].updatedDatetime._seconds >= fromDate && | |
| data.like[likeId].updatedDatetime._seconds < toDate; | |
| /* Number of “Like” – posts */ | |
| let isOwner = data.like[likeId].actor.userId === userId; | |
| if (isOwner && inRangeDate) { | |
| numberOfLikePost++; | |
| } | |
| /* Like – Agronomist’s Post */ | |
| isOwner = data.like[likeId].actor.userId === userId && | |
| data.like[likeId].actor.accountType === fn.EXPERT_ACCOUNT; | |
| if (isOwner && inRangeDate) { | |
| numberOfLikeAgronomistPost++; | |
| } | |
| } | |
| for (let likeId of Object.keys(data.replyLike)) { | |
| const inRangeDate = data.replyLike[likeId].updatedDatetime._seconds >= fromDate && | |
| data.replyLike[likeId].updatedDatetime._seconds <= toDate; | |
| /* Number of “Like” – comments */ | |
| let isOwner = data.replyLike[likeId].actor.userId === userId; | |
| if (isOwner && inRangeDate) { | |
| numberOfLikeReply++; | |
| } | |
| /* Like – Agronomist’s Comment */ | |
| isOwner = data.replyLike[likeId].actor.userId === userId && | |
| data.replyLike[likeId].actor.accountType === fn.EXPERT_ACCOUNT; | |
| if (isOwner && inRangeDate) { | |
| numberOfLikeAgronomistComment++; | |
| } | |
| } | |
| fn.updateCell(row, columns.numberOfLikePost, numberOfLikePost); | |
| fn.updateCell(row, columns.numberOfLikeReply, numberOfLikeReply); | |
| fn.updateCell(row, columns.numberOfLikeAgronomistPost, numberOfLikeAgronomistPost); | |
| fn.updateCell(row, columns.numberOfLikeAgronomistComment, numberOfLikeAgronomistComment); | |
| }, | |
| findNumberOfPost: (row, posts, userId, fromDate, toDate) => { | |
| const columns = fn.COLUMNS_EXCEL_MAPPING_SHEET1; | |
| let numOfQuestionPost = 0; | |
| let numberOfExpertConsultations = 0; | |
| let numberOfAgronomistPost = 0; | |
| for (let postId of Object.keys(posts)) { | |
| const inRangeDate = posts[postId].createdDatetime._seconds >= fromDate && | |
| posts[postId].createdDatetime._seconds < toDate; | |
| /* Number of Questions Posted – Community & Experts */ | |
| let isOwner = posts[postId].owner.userId === userId && | |
| posts[postId].postType === fn.PUBLIC_POST && | |
| posts[postId].tempFlag === fn.TEMP_POST_FLAG; | |
| if (isOwner && inRangeDate) { | |
| numOfQuestionPost++; | |
| } | |
| /* Number of 1-1 Expert Consultations */ | |
| isOwner = posts[postId].owner.userId === userId && | |
| posts[postId].postType === fn.PRIVATE_POST && | |
| posts[postId].tempFlag === fn.TEMP_POST_FLAG; | |
| if (isOwner && inRangeDate) { | |
| numberOfExpertConsultations++; | |
| } | |
| /* Number of Agronomist’s Post */ | |
| isOwner = posts[postId].owner.userId === userId && | |
| posts[postId].postType === fn.PUBLIC_POST && | |
| posts[postId].tempFlag === fn.TEMP_POST_FLAG && | |
| posts[postId].owner.accountType === fn.EXPERT_ACCOUNT; | |
| if (isOwner && inRangeDate) { | |
| numberOfAgronomistPost++; | |
| } | |
| } | |
| fn.updateCell(row, columns.numberOfQuestionsPostedCommunityAndExperts, numOfQuestionPost); | |
| fn.updateCell(row, columns.numberOfExpertConsultations, numberOfExpertConsultations); | |
| fn.updateCell(row, columns.numberOfAgronomistPost, numberOfAgronomistPost); | |
| }, | |
| addPostToSheetNumber: (workbook, posts, fromDate, toDate, sheetNumber = 1) => { | |
| const post = []; | |
| const startTime = new Date(); | |
| const sheet = workbook.getWorksheet(sheetNumber); | |
| console.log(`\r\nActual Post Count(Sheet ${sheetNumber}): ${Object.keys(posts).length}`); | |
| console.log('Add post between dates (YYYY-MM-DD): ' + moment(fromDate * 1000).format('YYYY-MM-DD') + ' and ' + | |
| moment(toDate * 1000).subtract('1', 'days').format('YYYY-MM-DD')); | |
| for (let postId of Object.keys(posts)) { | |
| const inRangeDate = posts[postId].createdDatetime._seconds >= fromDate && | |
| posts[postId].createdDatetime._seconds < toDate; | |
| if (inRangeDate) { | |
| const postDate = moment(posts[postId].createdDatetime._seconds * 1000).format('YYYY-MM-DD'); | |
| const postTime = moment(posts[postId].createdDatetime._seconds * 1000).format('HH:MM:SS'); | |
| const tag = Object.keys(posts[postId].tags || []).join(","); | |
| post.push([ | |
| posts[postId].subject, | |
| posts[postId].owner.displayName, | |
| postDate, | |
| postTime, | |
| tag, | |
| fn.parseBodyPreview(posts[postId].body) | |
| ]); | |
| } | |
| } | |
| sheet.addRows(post); | |
| sheet.eachRow((row, rowNumber) => { | |
| row.eachCell({ includeEmpty: true }, function (cell, colNumber) { | |
| sheet.getColumn(colNumber).hidden = false; | |
| cell.border = { | |
| top: { style:'thin' }, | |
| left: { style:'thin' }, | |
| bottom: { style:'thin' }, | |
| right: { style:'thin' } | |
| }; | |
| }); | |
| row.hidden = false; | |
| row.commit(); | |
| }); | |
| console.log(`Estimated Time(Add post in Sheet ${sheetNumber}): ${new Date().getTime() - startTime.getTime()}ms`); | |
| }, | |
| updateAnalyticExcel: async (data, filename, fromDate, toDate) => { | |
| const startTime = new Date(); | |
| fn.resetNumberCell(); | |
| const workbook = new Excel.Workbook(); | |
| const columns = fn.COLUMNS_EXCEL_MAPPING_SHEET1; | |
| await workbook.xlsx.readFile(filename); | |
| const sheet = workbook.getWorksheet(1); | |
| console.log(`Actual User Count(Sheet 1): ${sheet.actualRowCount - (_.max(fn.IGNORE_ROWS_EXCEL) || 0)}`); | |
| sheet.eachRow((row, rowNumber) => { | |
| if (!fn.IGNORE_ROWS_EXCEL.includes(rowNumber)) { | |
| let userId = row.getCell(columns.deviceId).value; | |
| fn.findNumberOfLike(row, data, userId, fromDate, toDate); | |
| fn.findNumberOfPost(row, data.post, userId, fromDate, toDate); | |
| row.eachCell({ includeEmpty: true }, function(cell, colNumber) { | |
| sheet.getColumn(colNumber).hidden = fn.IGNORE_COLUMNS_EXCEL.includes(colNumber); | |
| }); | |
| } | |
| row.hidden = false; | |
| workbook.views = [ | |
| { | |
| x: 0, y: 0, width: 10000, height: 20000, | |
| firstSheet: 0, activeTab: 0, visibility: 'visible' | |
| } | |
| ]; | |
| row.commit(); | |
| }); | |
| console.log('Filter data between dates (YYYY-MM-DD): ' + moment(fromDate * 1000).format('YYYY-MM-DD') + ' and ' + | |
| moment(toDate * 1000).subtract('1', 'days').format('YYYY-MM-DD')); | |
| console.log(`Update Cell: ${fn.updatedCells} of ${fn.cells} (${((fn.updatedCells/fn.cells) * 100).toFixed(2)}%)`); | |
| console.log(`Estimated Time(Filter & Edit data in Sheet 1): ${new Date().getTime() - startTime.getTime()}ms`); | |
| fn.addPostToSheetNumber(workbook, data.post, fromDate, toDate, 2); | |
| try { | |
| const startWriteTime = new Date(); | |
| console.log('\r\nRe-write file: ' + filename); | |
| await workbook.xlsx.writeFile(filename); | |
| console.log(`Estimated Time(Write file): ${new Date().getTime() - startWriteTime.getTime()}ms`); | |
| } catch (err) { | |
| console.error(err); | |
| } | |
| console.log(`\r\nEstimated All Time: ${new Date().getTime() - startTime.getTime()}ms`); | |
| } | |
| }; | |
| const fromDate = moment('2019-11-16').unix(), toDate = moment('2019-12-18').add(1, 'days').unix(); | |
| fn.updateAnalyticExcel(backup, source, fromDate, toDate); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment