How To Set A1notation For All Row (Just Set Column Initial) - google-apps-script

I want to Set Formula for some cell, depend on how much data I have.
The problem was, I can't write script to make Range without Row Initial ( e.g Range(A:AA)).
To make just Column Initial, I try to replace Parameter : lastCol and lastRow with blank string ('') , and Zero Number (0), but not work.
Thanks
function recap() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheetForm = sheet.getSheetByName('METER')
const sheetPrint = sheet.getSheetByName('CETAK TAGIHAN')
const n = 5
var lastRow = sheetForm.getLastRow()
var lastCol = n+4
const startRow = 7
const currentCol = 3
for (let i = 0 ; i < n; i++){
// FORMULA =vlookup((max(METER!A:A)),METER!A:I,5)
// HOW TO SET ALL COLUMN RANGE :(A:I) WITHOUT ROW NUMBER
sheetPrint.getRange(i+startRow,currentCol).setFormula('vlookup((max(METER!A:A)),METER!'+sheetForm.getRange(1,1,lastRow,lastCol).getA1Notation()+','+(5+i)+')');
}
}

In your situation, how about the following modification?
Modified script:
function recap() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheetForm = sheet.getSheetByName('METER')
const sheetPrint = sheet.getSheetByName('CETAK TAGIHAN')
const n = 5
const lastColumn = sheetForm.getLastColumn();
const columnIndexToLetter_ = index => (a = Math.floor(index / 26)) >= 0 ? columnIndexToLetter_(a - 1) + String.fromCharCode(65 + (index % 26)) : ""; // ref: https://stackoverflow.com/a/53678158
const columnLetter = columnIndexToLetter_(lastColumn - 1);
const formulas = [...Array(n)].map((_, i) => [`=vlookup((max(METER!A:A)),METER!A:${columnLetter},${i + 5})`]);
sheetPrint.getRange(7, 3, formulas.length).setFormulas(formulas);
}
When this script is run, the following formulas are put to the cells "C7:C11".
=vlookup((max(METER!A:A)),METER!A:I,5)
=vlookup((max(METER!A:A)),METER!A:I,6)
=vlookup((max(METER!A:A)),METER!A:I,7)
=vlookup((max(METER!A:A)),METER!A:I,8)
=vlookup((max(METER!A:A)),METER!A:I,9)
If the value of METER!A:I is constant, I think that the following modification might be able to be used.
function recap() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheetForm = sheet.getSheetByName('METER')
const sheetPrint = sheet.getSheetByName('CETAK TAGIHAN')
const n = 5
const formulas = [...Array(n)].map((_, i) => [`=vlookup((max(METER!A:A)),METER!A:I,${i + 5})`]);
sheetPrint.getRange(7, 3, formulas.length).setFormulas(formulas);
}
As another approach, the following modified script might be able to be used. In this case, the number values are removed from a1Notation.
function recap() {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheetForm = sheet.getSheetByName('METER')
const sheetPrint = sheet.getSheetByName('CETAK TAGIHAN')
const n = 5
const a1Notation = sheetForm.getRange(1, 1, 1, sheetForm.getLastColumn()).getA1Notation().replace(/\d/g, "");
const formulas = [...Array(n)].map((_, i) => [`=vlookup((max(METER!A:A)),METER!${a1Notation},${i + 5})`]);
sheetPrint.getRange(7, 3, formulas.length).setFormulas(formulas);
}
Note:
I think that when the formulas are put using setFormulas, the process cost can be reduced a little.

Related

Import Data From multiple sheet with a list of ID and specifics column

I have about many spreadsheet work with my partners and each partner use 1 spreadsheat for manage data.
I using a table to store all ID, Sheet name and column store data I need to import to my master sheet.
This is my Spreadsheet:
Link here
I using Appscript to do import data by read values in this table with 2 loop, I see it work to slow How could I speed up it?
this is my script
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Source Link');
var master = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master') ;
const dstLr = getLastPopulatedRow(ss); //get last row of Source Link
const target_sheet_name = ss.getRange(2,6,dstLr-1,1).getValues(); //Get data in Column F input to array
const ids = ss.getRange(2,1,dstLr-1,1).getValues(); //get data in column A input to array
const ebayID = ss.getRange(2,2,dstLr - 1,1).getValues(); //get cloumn index at Column B input to array
const team = ss.getRange(2,3,dstLr-1,1).getValues(); //get column containt team name at column C input to array
const linkOrder = ss.getRange(2,4,dstLr-1,1).getValues(); //get cloumn containt Link Order at column D input to array
const tracking = ss.getRange (2,5,dstLr-1,1).getValues(); //get column containt Tracking at column E input to array
const benCO = ss.getRange(2,7,dstLr,1).getValues();
ids.forEach((id, i) => {
const srcSheet = SpreadsheetApp.openById(id).getSheetByName(target_sheet_name[i]);
const lr = getLastPopulatedRow(srcSheet);
const srcCol = [ebayID[i], team[i], linkOrder[i],tracking[i]].flat();
for(var j = 0; j < srcCol.length; j++) {
const destCol = [1,2,3,4];
const destCol2 = [5];
destCols = destCol[j]
const srcRange = srcSheet.getRange(3, srcCol[j], lr); // Origin range to copy
const values = srcRange.getValues(); // Getting values from origin column
const destRange = master.getRange(2, destCols, lr);
master.clearContents;
destRange.setValues(values);
}
})
}
function getLastPopulatedRow(sheet) {
var data = sheet.getDataRange().getValues();
for (var i = data.length-1; i > 0; i--) {
for (var j = 0; j < data[0].length; j++) {
if (data[i][j]) return i+1;
}
}
return 0;
}
I also need add value of G column for each data I import from ID and Sheet name at colum A and column F, but when I try set value for column E at Master sheet I got error that "data have 1 but destination range have 582"
Could Some one give me advise
That's what I try
ids.forEach((id, i) => {
const srcSheet = SpreadsheetApp.openById(id).getSheetByName(target_sheet_name[i]);
const lr = getLastPopulatedRow(srcSheet);
const srcCol = [ebayID[i], team[i], linkOrder[i],tracking[i]].flat();
for(var j = 0; j < srcCol.length; j++) {
const destCol = [1,2,3,4];
const destCol2 = [5];
destCols = destCol[j]
const srcRange = srcSheet.getRange(3, srcCol[j], lr); // Origin range to copy
const values = srcRange.getValues(); // Getting values from origin column
const destRange = master.getRange(2, destCols, lr);
master.clearContents;
destRange.setValues(values);
}
const coName = [];
coName.push(benCO[i]);
master.getRange(2,5,lr,1).setValues(coName);
})
and this is error:
From your question and samples, how about the following sample script?
Sample script:
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceLink = ss.getSheetByName('Source Link');
const master = ss.getSheetByName('Master');
const srcValues = sourceLink.getRange("A2:G" + sourceLink.getLastRow()).getValues();
const header = ["Order ID", "Team", "ID", "ID TRACKING#"];
const values = [header, ...srcValues.flatMap(r => {
const sheet = SpreadsheetApp.openById(r[0]).getSheetByName(r[5]);
const [, h, ...v] = sheet.getDataRange().getValues();
const temp = h.map(e => e.trim());
const indexes = header.map(e => temp.indexOf(e));
return v.map(r => indexes.map(i => r[i]));
})];
master.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
In this sample script, first, the header is declared and the values are retrieved using the header from each sheet. And, the populated values are put into the destination sheet.
In this sample script, the header is used from your sample Spreadsheet. So, when you change the header titles, the result values might not be able to be used. Please be careful about this.
Reference:
map()
Added:
From your following reply,
I got messenger error at this line: const temp = h.map(e => e.trim()); messenger said: TypeError: e.trim is not a function
My proposed script is for your provided Spreadsheet, and when I tested my proposed script no error occurs. From your reply, I guessed that your Spreadsheet might be different from your provided Spreadsheet. If my understanding is correct, from your error message, I'm worried that the header rows might be changed. In your provided Spreadsheet, 1st 2 rows are header rows. But, if the header row is only the 1st row, the error might occur because the row values include the date object in the 2nd row. If my understanding is correct, can you test the following sample script?
Sample script:
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceLink = ss.getSheetByName('Source Link');
const master = ss.getSheetByName('Master');
const srcValues = sourceLink.getRange("A2:G" + sourceLink.getLastRow()).getValues();
const header = ["Order ID", "Team", "ID", "ID TRACKING#"];
const values = [header, ...srcValues.flatMap(r => {
const sheet = SpreadsheetApp.openById(r[0]).getSheetByName(r[5]);
// const [, h, ...v] = sheet.getDataRange().getValues();
let h;
let [h1, h2, ...v] = sheet.getDataRange().getValues();
if (h2.some(e => e instanceof Date)) {
h = h1;
v = [h2, ...v];
} else {
h = h2;
}
const temp = h.map(e => e.trim());
const indexes = header.map(e => temp.indexOf(e));
return v.map(r => indexes.map(i => r[i]));
})];
master.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
If the same error occurs and another error occurs, can you provide the sample Spreadsheet for correctly replicating the issue? By this, I would like to confirm it.

Is there an alternative to appendRow in AppsScript that only prints certain columns while leaving others in the row untouched

I'm building a calculator to use for pricing purposes. It has a primary "Calculator" sheet, where an admin can enter data and then generate a new result to the "DataLog" sheet. The "DataLog" sheet stores the results (columns A through X) and calculates the resulting price (columns Y through AO). There are also a few workflow columns that need to be present for each row (Columns AP through AS).
I am currently using appendRow() to print the data to the "DataLog" sheet. The issue is that appendRow() finds the first empty row, and since columns Y through AS are not empty because they contain necessary formulas/workflow, it prints to the bottom of the sheet. I am looking for a way to print the data where 1) it checks only a certain column for an empty row (column A or C, for example) and prints to that row, and 2) does not overwrite the formula/workflow columns (Y through AS).
Is there a way to do this using appendRow() or is there another function I should be using? Other than this one issue of where to print the results, everything works just as I want it to, but I cannot seem to find a way to resolve this issue.
EDIT: The reason the formula and workflow must be present within "DataLog" is that there are situations where after an entry has been filled out and printed changes need to be made to row, thereby changing the final price. So I cannot calculate the price within the function and print that as a static number.
Here is a copy of the calculator: https://docs.google.com/spreadsheets/d/1vsVZeOUUqhdiW1unz6dPuiP5yw24ENrv1-49kXqBnx4/edit#gid=0
Here is a copy of the code I am using:
function ClearCells() {
var sheet = SpreadsheetApp.getActive().getSheetByName('CALCULATOR');
sheet.getRange('G9:H9').clearContent();
sheet.getRange('G11').clearContent();
sheet.getRange('G14:H14').clearContent();
sheet.getRange('G6').clearContent();
sheet.getRange('I6').clearContent();
sheet.getRange('I17:I21').clearContent();
sheet.getRange('I24:I29').clearContent();
sheet.getRange('I32').clearContent();
sheet.getRange('K5').clearContent();
sheet.getRange('K15').clearContent();
}
function FinalizePrice() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceRangeFL = ss.getRangeByName('FirstLast');
const sourceValsFL = sourceRangeFL.getValues().flat();
const sourceRangeEN = ss.getRangeByName('EntityName');
const sourceValsEN = sourceRangeEN.getValues().flat();
const sourceRangeEP = ss.getRangeByName('EmailPhone');
const sourceValsEP = sourceRangeEP.getValues().flat();
const sourceRangeRT = ss.getRangeByName('ReturnType');
const sourceValsRT = sourceRangeRT.getValues().flat();
const sourceRangeRE = ss.getRangeByName('Returning');
const sourceValsRE = sourceRangeRE.getValues().flat();
const sourceRangeBQ = ss.getRangeByName('BasicQuestions');
const sourceValsBQ = sourceRangeBQ.getValues().flat();
const sourceRangeSEQ = ss.getRangeByName('SchEQuestions');
const sourceValsSEQ = sourceRangeSEQ.getValues().flat();
const sourceRangeEQ = ss.getRangeByName('EntityQuestions');
const sourceValsEQ = sourceRangeEQ.getValues().flat();
const sourceRangePYP = ss.getRangeByName('PYP');
const sourceValsPYP = sourceRangePYP.getValues().flat();
const sourceRangeADJ = ss.getRangeByName('Adjustment')
const sourceValsADJ = sourceRangeADJ.getValues().flat();
const sourceRangeAN = ss.getRangeByName('AdjustmentNote')
const sourceValsAN = sourceRangeAN.getValues().flat();
const sourceVals = [...sourceValsFL, ...sourceValsEN, ...sourceValsEP, ...sourceValsRT, ...sourceValsRE, ...sourceValsBQ, ...sourceValsSEQ, ...sourceValsEQ, ...sourceValsPYP, ...sourceValsADJ, ...sourceValsAN]
console.log(sourceVals)
const anyEmptyCell = sourceVals.findIndex(cell => cell === "");
if(anyEmptyCell !== -1){
const ui = SpreadsheetApp.getUi();
ui.alert(
"Input Incomplete",
"Please enter a value in ALL input cells before submitting",
ui.ButtonSet.OK
);
return;
}
const date = new Date();
const email = Session.getActiveUser().getEmail();
const data = [date, email, ...sourceVals];
const destinationSheet = ss.getSheetByName("DataLog");
destinationSheet.appendRow(data);
console.log(data);
sourceRangeFL.clearContent();
sourceRangeEN.clearContent();
sourceRangeEP.clearContent();
sourceRangeRT.clearContent();
sourceRangeRE.clearContent();
sourceRangeBQ.clearContent();
sourceRangeSEQ.clearContent();
sourceRangeEQ.clearContent();
sourceRangePYP.clearContent();
sourceRangeADJ.clearContent();
sourceRangeAN.clearContent();
ss.toast("Success: Item added to the Data Log!");
}
I know this is incomplete but for the purpose of discussion here's how I would clear content in your situation.
function ClearCells() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
sh.getRangeList(["G9", "G11", "G14:H14", "G6", "I6", "I17:I21", "I24:I29", "I32", "K5", "K15"]).getRanges().forEach(r => r.clearContent();)
}
If you wished to append the values of your individual ranges into a row you could do it like this:
function appendRangeValues() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const osh = ss.getSheetByName('Sheet1')
const rgl = sh.getRangeList(["G9", "G11", "G14:H14", "G6", "I6", "I17:I21", "I24:I29", "I32", "K5", "K15"]);
const rglb = breakUpRangeList(ss,sh,rgl);
const vs = rglb.getRanges().map(r => r.getValue());
Logger.log(JSON.stringify(vs))
osh.getRange(osh.getLastRow() + 1, 1, 1, vs.length).setValues([vs]);
}
But I'm guessing that you want to skip over cell functions and other columns so let me know what you want and may be we can find a solution that fits your needs
The breakUpRangeList function is something I wrote a while back to break up ranges into their individual cells which I find easier to deal with.
function breakUpRangeList(ss=SpreadsheetApp.getActive(),sh=ss.getSheetByName("Sheet0"),rgl) {
let b = [];
rgl.getRanges().forEach(rg => {
rg.getValues().forEach((r,i) => {
let row = rg.getRow() + i;
r.forEach((c, j) => {
let col = rg.getColumn() + j;
b.push(sh.getRange(row, col).getA1Notation())
})
})
})
b = [...new Set(b)];
Logger.log(JSON.stringify(b));
return sh.getRangeList(b);
}
Try this:
function appendRangeValues() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet0');
const osh = ss.getSheetByName('Sheet1')
const rgl = sh.getRangeList(["G9", "G11", "G14:H14", "G6", "I6", "I17:I21", "I24:I29", "I32", "K5", "K15"]);
const rglb = breakUpRangeList(ss,sh,rgl);
const vs = rglb.getRanges().map(r => r.getValue());
Logger.log(JSON.stringify(vs))
osh.getRange(getColumnHeight(3,osh,ss) + 1, 1, 1, vs.length).setValues([vs]);
}
function getColumnHeight(col, sh, ss) {
var ss = ss || SpreadsheetApp.getActive();
var sh = sh || ss.getActiveSheet();
var col = col || sh.getActiveCell().getColumn();
var rcA = [];
if (sh.getLastRow()){ rcA = sh.getRange(1, col, sh.getLastRow(), 1).getValues().flat().reverse(); }
let s = 0;
for (let i = 0; i < rcA.length; i++) {
if (rcA[i].toString().length == 0) {
s++;
} else {
break;
}
}
return rcA.length - s;
}

Trying to getlastrow

Hello I am trying to have a continual list that copies values from one sheet to another in google sheets. My problem is that it is overwriting on the second sheet. I can't figure out how to find the last row before it inserts values. Here is my code.
function SubmitData() {
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('Validation')
var drng = sht.getDataRange();
var rng = sht.getRange(6,2, drng.getLastRow(),drng.getLastColumn());
var rngA = rng.getValues();//Array of input values
var rngB = [];//Array where values that past the condition will go
var b = 0;//Output iterator
for(var i = 0; i < rngA.length; i++)
{
rngB[b]=[];//Initial new array
rngB[b].push(rngA[i][0],rngA[i][2]);
b++;
}
var shtout = s.getSheetByName('Track Data');
var outrng = shtout.getRange(2,1, rngB.length,2);//Make the output range the same size as the output array
outrng.setValues(rngB);
I don't see any condition in your code, you're just remapping
function SubmitData() {
const s = SpreadsheetApp.getActive();
const sht = s.getSheetByName('Validation');
const shtout = s.getSheetByName('Track Data');
const rng = sht.getRange(6, 2, sht.getLastRow() - 5, sht.getLastColumn() - 1);
const vs = rng.getValues();
let vO = vs.map(r => [r[0], r[2]]);
shtout.getRange(shtout.getLastRow() + 1, 1, vO.length, vO[0].length).setValues(vO);
}
Here is a modified script, easier to read. If you have the "sheet" in a variable you can call the getLastRow() method. Then plus 1.
You also can push an array inside an array.
Be aware that bad written functions can plus the lastrow. The "" will be see ad NOT empty. For instance:
//BAD:
=IF(A10 = "","","This is not empty")
//GOOD:
=IF(A10 = "",,"This is not empty")
The script:
function SubmitData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const inputSheet = ss.getSheetByName('Validation')
const inputValues = inputSheet.getRange(6,2, inputSheet.getLastRow(),inputSheet.getLastColumn()).getValues()
const output = [];
inputValues.forEach(row => {
output.push([row[0].row[2]])
})
const outputSheet = ss.getSheetByName('Track Data');
outputSheet.getRange(outputSheet.getLastRow() + 1,1,output.length,output[0].length).setValues(output)
}

How to iterate through a range and build a "table" based on a criteria, using Google Apps Script?

I got the following table to populate (range D6:J15) as I search the data in another sheet, based on a date criteria found in row 4:
This is where I'm to look for the data, considering Col A as the basis for the criteria:
My difficulty is to concatenate the data, as they meet the criteria.
This is the code I'm working on:
/* #OnlyCurrentDoc */
function editarPrevProd() {
const lock = LockService.getScriptLock();
lock.tryLock(3000);
if (lock.hasLock()) {
var sourceSheet = 'PrevProdDB2';
var destinationSheet = 'Previsão Entreposto';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var ActiveSheetName = ss.getActiveSheet().getName();
var LastRowSource = sheet.getLastRow();
var LastColumnSource = sheet.getLastColumn();
var values = sheet.getRange(2,1,LastRowSource,9).getValues();
var csh = ss.getSheetByName(destinationSheet);
var itens = csh.getRange("I40:J57");
var data = [];
var weekNo = csh.getRange("B4").getValue();
var weekDates = csh.getRange("D4:J4").getValues();
if (weekNo == "") {
Browser.msgBox("Escolher uma data e tente novamente!");
return;
}
//var clearRng = ["K34:K35", "N34:N35", "I40:K"];
//csh.getRangeList(clearRng).clearContent();
for (var i = 0; i < values.length; i++) {
if (values[i][7] == weekNo) {
data.push(values[i]);
//break;
}
}
var dias = 0;
var prevData = [];
for (var j = 0; j < weekDates.length; j++) {
dias = dias + 1;
Logger.log("Dias da Semana: " + dias);
for (var a = 0; a < data.length; a++) {
if (weekDates[j].valueOf() == data[a][0].valueOf()){
prevData.push(data[a][4]);
}
}
}
//map columns whose data will be set in the header.
var user = data.map(function(e){return e[5];});
var lastUpdate = data.map(function(e){return e[6];});
//Copy data array to destination sheet
csh.getRange("I1").setValue(user);
csh.getRange("I2").setValue(lastUpdate);
//csh.getRange("E6").setValue(timeStamp);
//If you wanted to set arrays in the form of
//a table, you'd use this below instead
var seg = data.map(function(e) {return [e[3]];});
var ter = data.map(function(e) {return [e[4]];});
var qua = data.map(function(e) {return [e[5]];});
var qui = data.map(function(e) {return [e[6]];});
var sex = data.map(function(e) {return [e[7]];});
var sab = data.map(function(e) {return [e[8]];});
var dom = data.map(function(e) {return [e[9]];});
//csh.getRange(6,4,data.length,1).setValues(seg);
lock.releaseLock();
}
}
Here's a sample of the file. Note that the gs file I'm working on is named SalvaPrevProducao.
https://docs.google.com/spreadsheets/d/1NOWkzQIAPPdZdxeeTR7Id2v8LR00_u06uPhHs3tzLuU/edit?usp=sharing
I believe your goal as follows.
You want to convert the above image to the bottom image using Google Apps Script.
The date header is the cells "D4:J4".
The source values are the cells "A6:M".
The column "M" of ID is Semana in the destination sheet.
In this case, I would like to propose the following flow.
Retrieve values from the source sheet.
Create an array for putting to the destination sheet.
Put the array to the destination sheet.
When this flow is reflected to the Google Apps Script, it becomes as follows.
Sample script:
Before you use this script, please set the variables of srcSheetName and dstSheetName.
function editarPrevProd() {
const srcSheetName = "Data Source"; // This is the source sheet name.
const dstSheetName = "destSheet"; // Please set the destination sheet name.
// This is from https://stackoverflow.com/a/44563639
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
// 1. Retrieve values from the source sheet.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName(srcSheetName);
const lastRow = srcSheet.get1stNonEmptyRowFromBottom(1);
const [[, , , ...header1], header2, ...srcValues] = srcSheet.getRange("A4:M" + lastRow).getValues();
// 2. Create an array for putting to the destination sheet.
const values = header1.reduce((ar, h, i) => {
srcValues.forEach(([a, b, c, ...dm]) => ar.push([h, a, b, c, dm[i] || 0, "", "", dm.pop(), h]));
return ar;
}, [["Data", "Tipo", "Cod", "Descrição", "Qtd", "Usuário", "TimeStamp", "Semana", "Data"]]);
// 3. Put the array to the destination sheet.
const dstSheet = ss.getSheetByName(dstSheetName);
dstSheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
When above script is run, the values are retrieved from srcSheetName and the converted values are put to dstSheetName .
Result:
When above script is run, the following result is obtained.
Note:
Unfortunately, from your question and sample Spreadsheet, I couldn't understand about Usuário and TimeStamp of the columns "F" and "G". At the sample output situation of Turn the data from the left into the format on the right side, Usuário and TimeStamp have no values.
References:
reduce()
forEach()
It is unclear why you would need to resort to scripting to look up those values, when a filter() formula would seem capable to do the same. Try this formula in cell D6:
=sum( iferror( filter(PrevProdDB2!$E$2:$E, PrevProdDB2!$B$2:$B = $A6, PrevProdDB2!$H$2:$H = $B$4, PrevProdDB2!$I$2:$I = D$4) ) )

Consolidate data into one master Google sheet using App Scripts

I am trying to consolidate data from multiple tabs into a consolidated sheet. Each tab is an individual form and has the same format. On the consolidated sheet, I want to re-arrange the data so the data field name is in a column, and data values are in rows. I tried the following:
function consolidateData(){
// defined all variables
var sheetNames = [];
var dataSheet = [];
var dataValues = [];
var conso=[];
var header = [["Faculty Name","Faculty ID","Date of Joining"]];
var ws = SpreadsheetApp.getActiveSpreadsheet();
// get all sheets
var allsheets = ws.getSheets();
for(var s in allsheets)
var sheet = allsheets[s];
sheetNames[s] = sheet.getName();
dataSheet[s] = ws.getSheetByName(sheetNames[s]);
// writing data into new sheet
var newSheet = ws.insertSheet().setName("Consolidated_Data");
newSheet.getRange("A1:C1").setValues(header);
var name = dataSheet[s].getRange("B1").getValue();
var id = dataSheet[s].getRange("B3").getValue();
var doj = dataSheet[s].getRange("B5").getValue();
var faculty = [(name),(id),(doj)];//convert into array
var facultycount = faculty.length;
for (var i = 0; i < faculty.length; i++)
//Loop through all rows and write them out starting on ROW2
{
newSheet.getRange(2 + i, 1).setValue(faculty[0]);//
newSheet.getRange(2 + i, 2).setValue(faculty[1]);//
newSheet.getRange(2 + i, 3).setValue(faculty[2]);//
}
}
There are four tabs and I expect to see results from each tab in the Consolidated_Data tab. But I only saw the last tab data got inserted repeatedly. Can anyone help? Thank you. Consolidated Data Sheet Example of an individual tab
While traversing through all your sheets, you haven't used curly braces after the for loop -
for(var s in allsheets)
So it's running the loop and the value of s stays at the last index of allsheets.
However, might I suggest a simplified version I have tested out -
function consolidateData () {
const headers = ["Faculty Name", "Faculty ID", "Date of joining"];
const rows = { "name": 0, "id": 2, "doj": 4 };
const consolidatedSheetName = "Consolidated_Data";
const ss = SpreadsheetApp.getActive();
const sheets = ss.getSheets();
let consolidatedValues = [];
// Setting headers
consolidatedValues.push(headers);
// Fetching values
for(let sheet of sheets) {
if(sheet.getName()==consolidatedSheetName) { continue; }
let data = sheet.getRange("B1:B5").getValues();
let faculty = [ data[rows.name][0], data[rows.id][0], data[rows.doj][0] ];
consolidatedValues.push(faculty);
}
// Adding to sheet
let consolidatedSheet = ss.getSheetByName(consolidatedSheetName);
if(!consolidatedSheet) {
consolidatedSheet = ss.insertSheet().setName(consolidatedSheetName);
}
let range = consolidatedSheet.getRange(1, 1, consolidatedValues.length, consolidatedValues[0].length); // 1, 1, 3, 3
range.setValues(consolidatedValues);
}
Issue:
The script is overwriting the same range here:
newSheet.getRange(2 + i, 1).setValue(faculty[0]);
Solution:
Add 1 for each row added:
newSheet.getRange(2 + i + s, 1).setValue(faculty[0]);
Or use sheet#appendRow()
newSheet.appendRow(faculty);
If you practice best practices, Your script can be simplified like this:
const consolidate = () => {
const ws = SpreadsheetApp.getActiveSpreadsheet(),
oldSheets = ws.getSheets(),
newSheet = ws.insertSheet().setName('Consolidated_Data');
newSheet.getRange(1, 1, 1 + oldSheets.length * 3, 3).setValues([
['Faculty Name', 'Faculty ID', 'Date of Joining'],
...oldSheets.map(sheet =>
sheet
.getRange('B1:B5')
.getValues()
.reduce((a, c, i) => (i % 2 === 0 ? [...a, c[0]] : a), [])
),
]);
};