I am writing a set of scripts in Google App Script, for a Google Sheet. I created a user interface to provide a web page experience for the Google Sheet, acting as a discussion forum. I store discussions in a recursive pattern, in the spread sheet, like this:
ID | Parent_ID | Title | Note | Forum_ID | Is_Active
1 | 0 | Some Title | Some Discussion | 100 | True
2 | 0 | Some Title | Some Discussion | 100 | True
3 | 2 | Some Title | Some Discussion | 100 | True
4 | 3 | Some Title | Some Discussion | 100 | True
5 | 2 | Some Title | Some Discussion | 100 | True
So, the nesting can be of an indeterminate number of levels. When the page loads, it call a script, passing in an ID, which will always be the root ID of upper node (where the Parent_ID is always 0). I then return a node, with all nested children. I then need to use the ID of each record in the nested group, to perform a couple of calculations. The code I have works, but can be very slow. To iterate over 20 records can take upwards of 15 seconds. Can anyone provide feedback on how to speed this up and make the code more efficient? Here is my code:
function GetMessageBoardChildren(message_id) {
console.time('Gettingcomments') //this block of code can take around 2-3 seconds to run through (where the number of records is about 50)
var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
var sheet = ss.getSheetByName(MESSAGE_BOARD);
var rows = sheet.getDataRange().getValues();
var newArray = [];
var CommentsArray = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
if (row[5] == 1) {
CommentsArray.push({
post_id: row[0].toString(),
parent_id: row[1].toString(),
forum_id: row[2].toString(),
title: htmlEscape(row[3].toString()),
message: htmlEscape(row[4].toString()),
is_active: row[5].toString(),
date_created: ConvertUnixTimeStampToDateTime(row[6].toString()),
created_by_id: row[8].toString()
})
}
}
console.timeEnd('Gettingcomments')
console.time('BuildgingTree')// this is fast. couple of miliseconds
tree = nest( CommentsArray );
for(var j = 0; j<tree.length; j++){
if(tree[j].post_id == message_id){
newArray.push(tree[j])
}
}
console.timeEnd('BuildgingTree')
console.time('recursing') //this can take 11-15 seconds to complete
var t = recursePosts(newArray);
console.timeEnd('recursing')
return t;
}
function recursePosts(posts){
for(var i=0;i<posts.length;i++){
if(posts[i].children){
recursePosts(posts[i].children)
}
console.time('GettingVotes')
var voteCount = GetVotesByCommentId(posts[i].post_id);
posts[i].number_up_posts = voteCount.upVote,
posts[i].number_down_posts = voteCount.downVote
console.timeEnd('GettingVotes')
console.time('GettingUsername')
posts[i].created_by = GetUserNameByUserId( posts[i].created_by_id);
console.timeEnd('GettingUsername')
posts[i].created_by_id="";
}
return posts;
}
const nest = (items, id = '0', link = 'parent_id') =>items
.filter(item => (item[link] === id ) )
.map(item => ({ ...item,children: nest(items, item.post_id) }));
function ConvertUnixTimeStampToDateTime(unix_timestamp) {
var a = new Date(unix_timestamp * 1000);
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = a.getMonth() + "/" + date + "/" + year + " " + hour + ":" + min + ":" + sec;
return time;
}
function htmlEscape(str){
//prevent injection
return str.replace(/<[^>]+>/g, "")
}
function GetUserNameByUserId(ID){
var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
var sheet = ss.getSheetByName(USERS);
var rows = sheet.getDataRange().getValues();
var userName = "";
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
if(row[0] === ID){
userName = row[3];
break;
}
}
if(userName == ""){
userName = "Admin"
}
return userName;
}
function GetVotesByCommentId(comment_id) {
var ss = SpreadsheetApp.openById(SPREAD_SHEET_ID);
var sheet = ss.getSheetByName(COMMENT_VOTES);
var rows = sheet.getDataRange().getValues();
var countUp = 0;
var countDown = 0;
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if (row[1] === comment_id && row[2] === 1) {
countUp++;
}else if (row[1] === comment_id && row[2] === -1){
countDown++;
}
}
return {upVote:countUp, downVote:countDown};
}