I am struggling with the following task: I have an folder with 20 spreadsheets that have all a datatable with the same format (same columns). I want to loop through all of them, collect the data, combine it to one big array and display it on a spreadsheet.
However, I am struggling to combine the arrays. In the first step I load the column headers from the final sheet. Afterwards I loop through all files (I have a table with the sheets ID stored in the array aFiles) but I cannot combine the arrays. I tried it with aData.concat but it didn't do anything.
function getInformation(){
var ssZ = SpreadsheetApp.getActiveSpreadsheet();
var sZu = ssZ.getSheetByName("Meldeeinheiten");
var aFiles = sZu.getDataRange().getValues();
var sDa = ssZ.getSheetByName("Data_komplett")
var aData = sDa.getRange(1, 1, 1, 15).getValues()
for (var iFile = 1; iFile<aFiles.length; iFile ++){
var org = aFiles[iFile][0];
var name = aFiles[iFile][1];
var id= aFiles[iFile][2];
var ssI = SpreadsheetApp.openById(id);
var sData = ssI.getSheetByName("Data");
var lRow = sData.getLastRow();
if (lRow >= 2){
var aNew =[];
aNew = sData.getRange(2, 1, sData.getLastRow(), 15).getValues();
aData.concat(aData,aNew);
}
}
var lDRow = sDa.getLastRow();
sDa.getRange(2, 1, lDRow , 15).clear()
var rng = sDa.getRange(1, 1, aData.length, 15);
rng.setValues(aData);
Logger.log(aData.length)
}
The data in the tables is strucutred in the following way:
Spreadsheet A:
Org Name Hours Comment
A Joe 15 Weekend
A Pete 20 Sunday
A Maik 15 test
Spreadsheet B
Org Name Hours Comment
B Will 15 Monday
B Anna 18 holiday
B Dave 10 test
...
And so one.
Has anybody an idea how I can combine those data and create a "joint database"?
Issue:
aData.concat(aData,aNew);
Array.concat doesn't concat in-place. It returns the concatenated array.
Solution:
Use the returned array:
aData = aData.concat(aData,aNew);
Alternatively use flatMap,
const out = aFiles.flatMap(([org, name, id])=>
SpreadsheetApp.openById(id)
.getSheetByName('Data')
.getDataRange()//TODO Modify range according to last row
.getValues())
Related
I am using google sheets quite a lot, but now I am trying to use google apps script to get and update dynamic data retrieved from formulas into a static table.
So, I have a sheet called 'dynamique', with formulas retrieving, filtering and sorting data from other spreadsheets.
I want to be able to work on this data, so I am trying to create a button which would copy all the values from the 'dynamique' sheet into another sheet called 'statique'. That is, I want a formula which would check if the values from the column C of the 'dynamique' sheet are in the column C of the 'statique' sheet. And if the values aren't there, I want the script to copy them. (columns A and B are empty)
I've managed to get my script to work for one column, but now, I want to copy the whole line.
For example, if the value in dynamique!C10 can't be found in statique!C:C, my script writes the value of dynamique!C10 in the first empty cell of the column statique!C:C. But I want it to write dynamique!C10:J10 into my destination sheet (say it's going to be maybe statique!C8:J8).
Here is my code, working for only one cell.
function dynamicToStatic() {
var dynSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dynamique");
var staSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("statique");
var dynLength = dynSheet.getRange("C1:C").getValues().filter(String).length;//.getLastRow();
var staLength = staSheet.getRange("C1:C").getValues().filter(String).length;
var staRange = staSheet.getRange(6,3,staLength-1);
var staValues = staRange.getValues();
var rangeToCheck = dynSheet.getRange(6,3,dynLength-1,8);
var valuesToCheck = rangeToCheck.getValues();
var numRows = rangeToCheck.getNumRows();
var staNumRows = staRange.getNumRows();
for (i = 0; i<= numRows; i++) {
var row = valuesToCheck[i];
var index = ArrayLib.indexOf(staValues , -1 , row);
if (index == -1) {
//if (staValues.indexOf(row) != -1) {
staSheet.getRange(i+6,3,1,8).setValues(row);
}
}
var timestamp = new Date();
staSheet.getRange(4,3).setValue('List updated on the: '+timestamp);
}
Now I can't manage to retrieve the whole line of the array, so as to be able to copy it using range.setValues(). I always get error messages.
Any help would be more than appreciated...
function gettingFullRows() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1');
const shsr=2;//data startrow
const vA=sh.getRange(shsr,1,sh.getLastRow()-shsr+1,sh.getLastColumn()).getValues();
let html='';
vA.forEach((r,i)=>{
html+=Utilities.formatString('<br />Row:%s is %s',i+shsr,r.join(','));
});
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), "Row");
}
So i did some re-writing to your code and made some comments in there. I hope this will make some things clear.
Array's are 0 indexed. So if the value is NOT found in the .indexOf then it would return -1. Also (for speed) i first push all the result to a array and then set the array in one "action" this saves a lot of time. The calls to and from a sheet takes the most time.
For the conversion to a 1d array i used spread operator
See this link for difference in const / var / let
The timestamp string i updated with the use of Template literals
If you have some questions, shoot! (also i did not test this ofcourse)
function dynamicToStatic() {
const dynSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("dynamique");
const staSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("statique");
const dynValues = dynSheet.getRange(1,3,dynSheet.getLastRow(),8).getValues();
//This is a 2d array
const staRaw = staSheet.getRange(6, 3, staSheet.getLastRow()).getValues();
//Convert to 1d array, for the indexoff later on, this way it is easier.
const staValues = [].concat(...staRaw);
//to store the output, as a 2d array, inside the if you see i push it in as array so you have the 2d array for the setValues.
const output = [];
for (let i = 0; i < dynValues.length; i++){
//i = the index of the array (row) inside the array of rows, the 0 would be the values of column C.
if (staValues.indexOf(dynValues[i][0]) >= 0){
output.push([dynValues[i]]);
}
}
//Start by the lastrow + 1, column C(3), ouput is a array of arrays(rows), then get the [0].lengt for the columns inside the row array.
staSheet.getRange(staSheet.getLastRow()+1, 3, output.length, output[0].lenght).setValues(output);
const timestamp = new Date();
staSheet.getRange(4,3).setValue(`List updated on the: ${timestamp}`);
}
I have two arrays
Ary1 has n columns and length p
its tabular data looks like
Ary2 has 5 columns and length q
Its tabular data looks like
I output the data like this
sh.getRange(1, 1, Ary1.length, Ary1[0].length).setValues(Ary1);
sh.getRange(sh.getLastRow()+1, 1, Ary2.length, Ary2[0].length).setValues(Ary2);
I want to append an Ary2 under Ary1 to get the result array of length p+q
with tabular data
So I only have to output the data once
I have tried
var result = Ary1.concat(Ary2);
sh.getRange(1,1,result.length,result[0].length).setValues(result);
and
Ary1.push(...Ary2);
sh.getRange(1,1,Ary1.length,Ary1[0].length).setValues(Ary1);
sh.getRange(1,1,result.length,result[0].length).setValues(result);
But I get
The number of columns in the data does not match the number of columns in the range. The data has 5 but the range has 25.
It would be best to mutate Ary1 or Ary2 then to create a new array
Thank you
I think that the reason of your issue is the difference of the column length of each array. In order to avoid this, it is required to be the same length for each column in the array. So I would like to propose the following modification.
Pattern 1:
In this pattern, Spreadsheet service is used.
Modified script:
var Ary1 = ,,, // Please set the value.
var Ary2 = ,,, // Please set the value.
if (Ary1[0].length > Ary2[0].length) {
var len = Ary1[0].length - Ary2[0].length;
Ary2 = Ary2.map(r => r.concat(Array(len).fill("")));
} else if (Ary1[0].length < Ary2[0].length) {
var len = Ary2[0].length - Ary1[0].length;
Ary1 = Ary1.map(r => r.concat(Array(len).fill("")));
}
var values = Ary1.concat(Ary2);
sh.getRange(1, 1, values.length, values[0].length).setValues(values);
Pattern 2:
In this pattern, Sheets API is used. When the Sheets API is used, it is not required to be the same column length in the array.
Modified script:
Before you use this script, please enable Sheets API at Advanced Google services.
var spreadsheetId = "###"; // Please set Spreadsheet ID.
var sheetName = "Sheet1"; // Please set sheet name.
var Ary1 = ,,, // Please set the value.
var Ary2 = ,,, // Please set the value.
var values = Ary1.concat(Ary2);
Sheets.Spreadsheets.Values.update({values: values}, spreadsheetId, sheetName, {valueInputOption: "USER_ENTERED"});
References:
map()
Method: spreadsheets.values.update
I am working with different 2d arrays (rows and columns, google app script). For instance (r = row, c = column):
var array1 =
[[r1c1, r1c2, r1c3],
[r2c1, r2,c2, r2c2]]
var array2 =
[[r1c4, r1c5],
[r2c4, r2c5],
[r3c4, r3c5]]
and I want to have it like that:
var array1and2 =
[[r1c1, r1c2, r1c3, r1c4, r1c5],
[r2c1, r2c2, r2c3, r2c4, r2c5],
[empty, empty, empty, r3c4, r4c5]
]
It doesn't have to be empty but as already said I want to display it in google spreadsheets. The second array should be in the first empty row and column next to the first array.
I hope it is understandable and thank you very much for you help!
Somethink like this you can do:
var array2 = [['r1c4', 'r1c5'],
['r2c4', 'r2c5'],
['r3c4', 'r3c5']];
var array1 = [['r1c1', 'r1c2', 'r1c3'],
['r2c1', 'r2,c2', 'r2c2']];
var result = array2.map((elem, i)=>[...(array1[i] || new Array(array1[0].length).fill('empty')), ...elem]);
console.log(result);
I'm reading your question as being about not just how to create an amalgamated array but actually to manipulate the data in situ, so I'd approach it something like this (assuming that array 1 lives on sheet1 and array 2 lives on sheet2:
function translateArray(){
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getSheetByName("Sheet1");
var os = sh.getSheetByName("Sheet2");
var range1 = ss.getRange("A1:C2");//2 rows 3 columns
var range1Width = range1.getValues()[0].length;//checks length of first row - the width
var range2 = os.getRange("A1:B3");//3 rows 2 columns
var data = range2.getValues();
ss.getRange(1,range1Width,data.length, data[0].length).setValues(data);
}
This code copies the data in sheet2 to sheet 1 alongside it.
use [1] instead of [0] in range1Width if you have header data wider than the real data.
A less orthodox approach:
function merge2Arrays() {
var array1 = [['r1c1', 'r1c2', 'r1c3'],['r2c1', 'r2,c2', 'r2c3']];
var array2 = [['r1c4', 'r1c5'],['r2c4', 'r2c5'],['r3c4', 'r3c5']];
const ss=SpreadsheetApp.getActive();
const sh=ss.insertSheet('xxxxx');
sh.getRange(1,1,array1.length,array1[0].length).setValues(array1);
sh.getRange(1,array1[0].length+1,array2.length,array2[0].length).setValues(array2);
const a=sh.getDataRange().getValues();
ss.deleteSheet(sh);
ret a;
}
function merge3Arrays() {
var array1 = [['r1c1', 'r1c2', 'r1c3'],['r2c1', 'r2,c2', 'r2c3']];
var array2 = [['r1c4', 'r1c5'],['r2c4', 'r2c5'],['r3c4', 'r3c5']];
var array3 = [["r1C6"],["r2c6"],["r3c6"],["r4c6"],["r5c6"],["r6c6"]];
const ss=SpreadsheetApp.getActive();
const sh=ss.insertSheet('xxxxx');
sh.getRange(1,1,array1.length,array1[0].length).setValues(array1);
sh.getRange(1,array1[0].length+1,array2.length,array2[0].length).setValues(array2);
sh.getRange(1,array1[0].length + array2[0].length + 1,array3.length,array3[0].length).setValues(array3);
const a=sh.getDataRange().getValues();
ss.deleteSheet(sh);
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(JSON.stringify(a)), "Display Array");
}
Firstly I am very inexperienced here so apologies if this is obvious.
I have an array of data that updates automatically and I wish to copy this data out so I have an archive of it.
I have managed to find the following script which works for what I want:
function saveInstaPostData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("xxx");
var data0 = sheet.getRange("xxx!A2:AQ21").getValue();
var data1 = sheet.getRange("xxx!B2").getValue();
var data2 = sheet.getRange("xxx!C2").getValue();
var data3 = sheet.getRange("xxx!D2").getValue();
sheet.appendRow([data1,data2,data3,...]);
}
However I have a range of 860 cells, so doing it one by one isn't too feasible.
Reading up on the appendRow method I realise that it (seems) to only be able to append one row at a time. I only have 20 rows so this should still be doable.
I then tried using
function saveInstaPostData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Insta faction post data");
var values = sheet.getSheetValues(2, 1, 1, 43);
sheet.appendRow([values]);
However this outputs the following in the first cell of the new row: [Ljava.lang.Object;#247f2c9a
This seems to be the array I'm trying to append (java: what is this: [Ljava.lang.Object;?) however I can't get it to work!
[I have also tried using
function saveInstaPostData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Insta faction post data");
var range = sheet.getRange(2,1,20,43);
var values = range.getValues();
sheet.appendRow([values]);
This outputs ' Range ' in the first cell of the new row.
]
Any pointers would be really appreciated,
Thanks,
On your example, you try to append a tri dimensionnal array:
var values = sheet.getSheetValues(2, 1, 1, 43);
or
var range = sheet.getRange(2,1,20,43);
var values = range.getValues();
Your "values" variable contains a bi dimensionnal array, that you've put in a mono dimensionnal array:
sheet.appendRow([values]); // [values] put bi dimensionnal array in a mono dimensionnal array
To append your data, you need to append each row of your array, one after a other like :
for(var i=0; i<values.length;i++){
sheet.appendRow(values[i]);
}
I am pretty new to this forum and also to the google scripts. I have never actually learned JavaScript or any other programming language, however I was forced to start using then since the time I chose the google apps as my main platform for my small business.
My problem is in google ImportRange function limitation to 50 on every spreadsheet. I created a model, where every customer has his own spreadsheet with his personal data, deadlines, etc. located in his own folder in google drive.
I also created a spreadsheet called "Organizer", Organizer has two functions -
1) create automatic correspondention using autoCrat script,
2) show deadlines for every costumer and sort them by priority.
So i need to be able to share / import / copy data from all customer spreadsheets to the "Organizer". Because there are 50+ costumer spreadsheets, I had to give up on ImportRange function and instead of that I am using a simple script to copy files from every spreadsheet directly:
function ImportDataRange() {
// rown number.1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var range = sheet.getRange(2, 1)
var id = range.getValue()
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange("B2:AC2").setValues(data)
// row number.2
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var range = sheet.getRange(3, 1)
var id = range.getValue()
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange("B3:AC3").setValues(data)
}
This script actually works well, but problem is, when I want to add new costumer spreadsheet to "Organizer" using this method, I have to manually add new copy of whole code for every new row and also change the output range of imported data and location of source file ID in "Organizer".
Does anybody know some kind of workaroud, which will help me to add new rows / costumer data easier / automatically ?
Thank you for your help!
You are going to want to use a loop of some sort. I haven't tested the code below, but based on your example, I think this should work for you.
function ImportOtherSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
// Get the first column
// lastRow() - 1 because we're starting at row 2
var sheetIds = sheet.getRange(2, 1, sheet.getLastRow() - 1);
// For each ID in the id column
for (var i = 0; i < sheetIds.length; i++) {
var id = sheetIds[i]; // Get the id from the Array
// Get the new sheet, range and values
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
// Get the local range, and write the values
sheet.getRange(i + 1, 2, 1, data[0].length).setValues(data)
}
}
As you learn more about GAS and JS, take advantage of MDN and the GAS Documentation
I took the fooby´s code and after long trial-and-error procedure I came with code that is working for me, so if anyone is interested, here it is:
function ShowDataFromOtherSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Databaze");
var ids = sheet.getRange(2, 1, sheet.getLastRow() - 1).getValues();
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
var ssraw = SpreadsheetApp.openById(id);
var sheetraw = ssraw.getSheetByName("Raw");
var range = sheetraw.getRange("A2:AB2");
var data = range.getValues();
sheet.getRange(i + 2, 2, 1, data[0].length).setValues(data)
}
}
And thank you fooby - i would not make it without your help!