Pulling scattered data from changing spreadsheet - loops

I'm trying to write a script which has multiple parts. The current part (function copyOver) supposed to open a spreadsheet (by ID), extract specific data from it and insert it into a Master spreadsheet.
The part I'm stuck with is that the spreadsheet changes daily. Some days there are cells containing data of "Sea Water", other days there aren't any. Ideally, I was trying to write a script which loops through the sheet looking for the specific tab names in cells (for example: Sea water, chlorine content...) and extract the data from the row below, up until the second tab and so on. I would only need very specific data, like data from "C6", "E6", "F10", but these cells are always changing so I have to look for them by using the tab names in cells above them. There would be multiple arrays for each tab and the data coming with it.
Would that be possible to extract data this way and put them into an array containing the tab value as the header or title and the data connected to that specific tab.
var sourceID = "source sheet ID";
var main = SpreadsheetApp.openById("master sheet ID"); // MASTER
var source = SpreadsheetApp.openById(sourceID); //the workbook you're copying from
var mainsheet = main.getSheetByName("Lab Data"); // the sheet you want to copy the stuff into
var sourcesheet = source.getSheetByName("ANALYSIS REPORT"); // the sheet you're copying from
var dataRange = sourcesheet.getDataRange().getValues(); // gets sheet as data range
// finds SEA WATER tab in cell and gets the range below until the end of the document
// this is the range I need to find the rest of the tabs and the data under them.
var cont = "SEA WATER";
var i = [];
for (var y = 0; y < dataValues.length; y++){
if(dataValues[y] == cont){
i.push(y);
} // end if
} // end for
Logger.log(i);
var Row = Number(i)+Number(dataRange.getRow()); // gets the row number of SEA WATER tab
Logger.log("row number: " + Row);
var swLast = sourcesheet.getLastRow();
var swRange = sourcesheet.getRange(Row,2,swLast,11);
var swValues = swRange.getValues(); // range of needed information
Logger.log("sw: " + swValues);
var con2 = "SW outlet SW from Coarse filtration"; // looking for the secondary tab, within the
range
I got from the first loop
var res2 = [];
for(var i2 = 0; i2 < swValues.length; i2++) {
if(swValues[i2][4] === con2) res2.push(data[i2])
var row2 = Number(i2)+Number(swRange.getRow());
Logger.log("row2 " + row2);
} // for end
var look1 = "SW outlet SW from Coarse filtration ";
for(var i1 = 0; i1<dataRange.length;i1++){
if(dataRange[i1][1] == look1){
return i1+1;
}
}
Logger.log((i1+1));
} // end of function
EDIT: Here's a link to a sheet. Required data starts from row 237, until row 268 - but this can change every day. (Deleted the information for privacy reasons.)
Basically, I need all the cells with "x" in them, preferably together with the title cells above them, so I'll know what data it is.

The following code loops through your headers in column B and finds the row in which your header of interest is located
Subsequently, it copies the data starting from this row to the last data row into the sheet "Lab Data":
function myFunction() {
var sourceID = "source sheet ID";
var main = SpreadsheetApp.openById("sourceID"); // MASTER
var source = SpreadsheetApp.openById(sourceID); //the workbook you're copying from
var mainsheet = main.getSheetByName("Lab Data"); // the sheet you want to copy the stuff into
var sourcesheet = source.getSheetByName("ANALYSIS REPORT"); // the sheet you're copying from
var dataRange = sourcesheet.getDataRange()
var dataValues=dataRange.getValues(); // gets sheet as data range
for (var a = 0; a < dataValues.length; a++){
if(dataValues[a][1]=="SEA WATER"){
var Row=a+1;
break;
}
}
if(Row){
var swLast = sourcesheet.getLastRow();
var swRange = sourcesheet.getRange(Row,2,swLast,11);
swRange.copyTo(mainsheet.getRange(mainsheet.getLastRow()+1, 2));
}
} // end of function
I hope this helps to solve your issue.

Related

Apps Script: Move SELECTED rows from one sheet to the last available rows of another sheet

The code below is from here and was originally written by user #Cooper. All it does is that it copies the values of the columns specified in the array colA = [1,3,2,4] from SHEET 1 and add them to SHEET 2. I want to re-write the 2 last lines of the code, so that the values coming from SHEET 1 are added to the last available rows in SHEET 2. By "2 last lines", I mean these last lines of the code:
drng = des.getRange(1,1,drngA.length,drngA[0].length);//destination array controls size of destination range.drng.setValues(drngA);
Any idea how to get this done?
Thank you so much in advance for your help!
function Copy_data()
{
var src = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEET 1");
var des = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEET 2");
var srng = src.getDataRange();
var srngA = srng.getValues();
var drngA = [];
var colA = [1,3,2,4];//indirect data column selection
for (var i = 0; i < srngA.length;i++ )
{
var k = 0;
drngA[i]=[];
for(var j=0;j<srngA[i].length;j++)
{
drngA[i][k++] = srngA[i][colA[j]-1];
}
drng = des.getRange(1,1,drngA.length,drngA[0].length);//destination array controls size of destination range.
drng.setValues(drngA);
}
}
You can get the last row of the destination Sheet and after, add it to your getRange() function. The method proposed by #soMario will not work because it makes requests inside the loop while you update the Sheet, and this causes it to get different values every time you call des.getLastRow().
The simplest solution is to take the getLastRow() request outside of the loop and then include it in getRange. Note that one is added to it so that it does not overwrite the last row with the setValue() request.
Code.gs
function Copy_data() {
...
var lastRow = des.getLastRow() + 1
for (var i = 0; i < srngA.length;i++ ){
...
drng = des.getRange(lastRow,1,drngA.length,drngA[0].length)
...
}
Documentation
getRange(row, column, numRows, numColumns)
getLastRow()

get the cell containing a specific data in appscript

I'm trying to set a follow up of unpaid invoices.
For that I'd like to find a way to get to the cell of a specified invoice number.
For example, I need to go the cell containing 6126944 in the column H in the sheet follow up
This number will always be typed in the cell D16, of the sheet "first call".
Is there any way to do that, I'm quite new on appscript
If you need just to jump to the next sheet cell (column H) that contains the same number as the cell D16 -- here is the way:
function jump_to_cell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet_first_call = ss.getSheetByName('First call');
var sheet_follow_up = ss.getSheetByName('Follow up');
var num = sheet_first_call.getRange('D16').getValue();
var nums = sheet_follow_up.getRange('H:H').getValues().flat().filter(String);
for (var row in nums) {
if (nums[row] == num) {
sheet_follow_up.getRange('H'+(row+1)).activate();
break;
}
}
}

Cannot call method "push" of undefined

I'm trying to make a spreadsheet to upload products in Prestashop by .csv. Everything works like a charm, but now I need to be able to make some changes in already entered products with the same spreadsheet. The only thing I came up with is to manipulate text strings from a cell into a variable array (after that I'll find a way to go forward).
Firstly I managed to combine about ~100 cells into one cell (which I accomplished with a complicated formula) but now I need the text from this cell to be separated and temporarily stored in an array variable.
This is the formula. It's joining columns in rows with a : separator and then joins those rows with a ; separator and in the end I just needed a number:
=regexreplace(regexreplace(regexreplace(concatenate(arrayformula(if($A$13:$A$50="","",if($C$13:$C$50="","",$A$13:$A$50&":"&$C$13:$C$50&if($D$13:$D$50="","",$D$13:$D$50)&":"&(ROW($A$13:$A$50)-12)&";"))))," :",":"),": ",":"),"\+","-")
This resulted in this text:
Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR
Premium:4;Culoare:Gold:5;Culoare curea:Light
brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip
ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare
(ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric
altimeter, Accelerometer, Smart notifications, Weather, Step counter,
Move bar, Calories burned, Floors climbed, Analog
hands:26;Garanție:24luni:38;
Now I need to separate everything back as it was, but by a code in Apps Script, so that I will be able to manipulate the values separately, but they would still be in a structured form.
It should be something like this (inside a two dimensional variable):
[0][0]Producător [0][1]GARMIN
[1][0]Tip [1][1]Ceas inteligent
[2][0]Model [2][1]Vivomove HR Premium
[3][0]Culoare [3][1]Gold
[4][0]Culoare curea [4][1]Light brown
[5][0]Greutate [5][1]56.5g
[6][0]Rezolutie display [6][1]64x128
[7][0]Tip ecran [7][1]OLED
[8][0]GPS [8][1]Da
[9][0]Bluetooth [9][1]Da
[10][0]Durata in regim de asteptare (ore) [10][1]168
[11][0]Sensori [11][1]Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands
[12][0]Garanție [12][1]24luni
And now the main part... The next code is breaking with the error Cannot call method "push" of undefined
//var ss = SpreadsheetApp.getActiveSpreadsheet();
//var activeSheet = ss.getActiveSheet();
//var idSpreadsheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1zRsGMoXJzG9oht_pr3Rr24ksPqBzTZIvNcYPUKfphNI/edit#gid=1264546658").getSheetByName("RO").getDataRange().getValues();
//var idToChange = activeSheet.getRange("A12").getValue();
var row = 0;
//var userID = Session.getActiveUser();
var bufferFeatures = [{}];
bufferFeatures = idSpreadsheet[10][29];
var bufferImages = idSpreadsheet[row][27];
//var productRows = bufferFeatures.indexOf(";",0);
var testColumn = [];
var pos = 0; //here is where we start the text string
var del = 0; //here is where we find the ";" delimiter and stop slicing text string
// THIS FOR LOOP WORKS FINE
for (pos = 0; pos < bufferFeatures.length; pos = del) {
del = bufferFeatures.indexOf(";", pos);
testColumn.push(bufferFeatures.slice(pos, del));
del++;
};
var rownr = 0; //current row number.. not really using this variable
var pos1 = 0; //here is where we start the text string
var del1 = 0; //here is where we find the ":" delimiter and stop slicing text string
var columnsAndRows = [];
columnsAndRows.push([]);
var j = 0;
//THIS FOR LOOP GIVES ME TROUBLE
for (var x = 0; x <= testColumn.length; x++) {
for (pos1 = 0; pos1 + 1 < testColumn[x].length; pos1 = pos1) {
del1 = testColumn[j].indexOf(":", del1);
var theSlice = testColumn[j].slice(pos1, del1);
var theStop = testColumn[j].length;
//for some reason, I can't get this code to "push" j=2)
Logger.log("Adding " + theSlice);
columnsAndRows[j].push(theSlice);
del1++;
pos1 = del1;
Logger.log("Added")
}
Logger.log("Next row");
del1 = 0
j++;
//rownr++;
};
You need to declare columnsAndRows[j] as a array too.
columnsAndRows[j] = [];
Using split() would be much easier:
function strToArr(string) {
if (!string) {
var string = "Producător:GARMIN:1;Tip:Ceas inteligent:3;Model:Vivomove HR Premium:4;Culoare:Gold:5;Culoare curea:Light brown:6;Greutate:56.5g:8;Rezolutie display:64x128:9;Tip ecran:OLED:10;GPS:Da:15;Bluetooth:Da:16;Durata in regim de asteptare (ore):168:24;Sensori:Heart RATE, Activity Tracker, Barometric altimeter, Accelerometer, Smart notifications, Weather, Step counter, Move bar, Calories burned, Floors climbed, Analog hands:26;Garanție:24luni:38; "
}
var arr1 = string.substr(0, string.lastIndexOf(";")).split(';'); //split by ;
var arr2 = arr1.map(function(e) { return e.split(':').slice(0,2)}); //split each element of arr1 by : and return only the first two elements
Logger.log(arr2);
return arr2;
}

for loop not iterating over last element of 2D array in google app script (GAS)

I am working on a script that, in part, takes an array of names, compares each name to column A in a sheet, and returns with a row matched value in column B. (Like the vLookup command in sheets)
The setup
var ss = SpreadsheetApp.getActiveSpreadsheet();
var clientsSheet = ss.getSheetByName("Clients");
var cRow = clientsSheet.getLastRow();
var cColumn=clientsSheet.getLastColumn();
var cData=clientsSheet.getRange(1,1,cRow,cColumn).getValues(); //create array of client data
The trouble code
//put each client on their own row and add hour
for(i=0; i < client.length; ++i){
var cl = client[i]
//iterate over array of clients (column A) and hours (Column B) to find match and log the number in column B
for(j=0;j<cData.length;++j){
if (cData[j][0]==cl){
var hour = cData[j][1];
}
}
//return the matched values
Logger.log(cl+" - "+hour);
}
The var 'client' is an array that was split from a list of names in a single cell that are separated by commas (see whole code below)
At the moment it works great except that it misses the last element in the array.
for example:
if I have a sheet with two columns and three rows like so:
A 1
B 2
C 3
I would get back
A-1
B-2
C-
It is missing that last piece on the last element - it should be
A-1
B-2
C-3
I am stumped, and I know that it must be some simple little thing.
Any help would be amazing
Thanks!
The Code:
function logClients()
/*
Take data from a google form check box submissions. Check box submissions put all checked answers into a single cell separated by a comma. The function first takes the most recently submitted row, removes unneeded spaces, and splits each element into its own part of an array.
Then, the function compares each clients name in the array to a sheet with other info, such as the default number of hours we meet. It takes the clients name, the date of submission, and the hours, and logs them on a new row in two different sheets, the Hours sheet and the Trans Log sheet.
*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName("Log"); //Raw data from the Google form
var hourSheet = ss.getSheetByName("Hours"); //logged data for my records, separated into individual clients
var transLog = ss.getSheetByName("Trans Log"); // logged data minus "other" catagory
var clientsSheet = ss.getSheetByName("Clients"); //sheet containing all clients names and the typical hours we meet
var lRow = logSheet.getLastRow();
var hRow = hourSheet.getLastRow();
var tRow = transLog.getLastRow();
var cRow = clientsSheet.getLastRow();
var cColumn = clientsSheet.getLastColumn();
var cData = clientsSheet.getRange(1, 1, cRow, cColumn).getValues();
//get list of clients from cell and split it into an array
var Client = logSheet.getRange(lRow, 2).getValue().replace(", ", ","); //remove all spaces after a comma
var client = Client.split(",");
//get "other" information and do the same
var Other = logSheet.getRange(lRow, 5).getValue().replace(", ", ",");
var other = Other.split(",");
//check the date and set to today if nothing else has been entered
var dcell = logSheet.getRange(lRow, 4).getValue();
var date = new Date()
if (dcell == "") {} else if (dcell == "Yesterday") {
date = new Date(date.getTime() - 1 * (24 * 3600 * 1000));
} else {
date = dcell
}
var date = Utilities.formatDate(date, "GMT-8", "MM/dd/yy"); //format date
//put each client on their own row
for (i = 0; i < client.length; ++i) {
var cl = client[i]
var hour = logSheet.getRange(lRow, 3).getValue(); //hours
if (hour == !"") {
break;
}
for (j = 0; j < cData.length; ++j) {
if (cData[j][0] == cl) {
var hour = cData[j][1];
}
}
Logger.log(date + " - " + cl + " - " + hour);
hourSheet.appendRow([date,cl, hour]);
transLog.appendRow([date, cl, hour]);
}
//put each client on their own row
for (i = 0; i < other.length; i++) {
hourSheet.appendRow([date, other[i], getHour(client[i])]);
}
} //end of function
``
This is a code that I have been working on to teach myself Java and Apps-script
Yup, simple mistake.
Not all of the spaces before each name were being removed from the array, so the if statement would skip right over them because they were not a true match

Get data from a lot of different sheets with a script in Google Spreadsheet

I have a spreadsheet containing 50 sheets, named "1", "2", "3". The very first sheet is a summary, gathering specific information from the different sheets. The simple way to fill it in is by using ='1'!B5 and so on. What I want to do is enter that formula into a script and have it pull the specified data from all the different sheets on new rows. So that info from sheet 1 is at row 1, info from sheet 2 is on row 2.
The reason I don't want to do it manually is that I have 14 cells that I need to pull and insert into 4 different overviews from 50 sheets and 2 spreadsheets where I need to do this. Adding up to 5600 functions that I would need to change manually.
The reason I named the sheets in this simple manner is that I know it enables me to write this kind of function. A variable that increases its value by 1 for every loop and outputs the function on a new row with every loop, for instance
var sheetName = 0;
output.setValue('='' + sheetName + ''!B5');
I know I should have a variable for the specified output cell that also increase its value by 1 for every loop. But I have no idea how to get this sorted out, my scripting skills only allow me to modify others script to make them suit my own purposes but not write anything by myself and I have been unable to figure this one out more then the theory behind it. I know this isn't the place to ask for ready made code so I don't demand or even expect a solution, I just felt I had to try and ask for aid.
Here is a dummy which shows what I'm trying to do.
https://docs.google.com/spreadsheet/ccc?key=0ArjDeqGD779cdEh2Ynh5ODBFQVFkVE9lX0p4aWpXelE&usp=sharing#gid=0
You are a lucky man Mattis! I was doing this thing myself earlier this week so I have added a full working script to your dummy sheet. I'll add a copy here for completeness. Any questions please let me know :)
function populateOverview() {
//set basics
var ss = SpreadsheetApp.getActiveSpreadsheet();
var viewSheet = ss.getSheetByName('Overview');
var dataLength = 4; //this is how many cells from each sheet
//create array of sheet names and remove 'overview'
var sheetNames = getSheetNames();
var overviewIndex = sheetNames.indexOf('Overview');
sheetNames.splice(overviewIndex, 1);
//set initial data and target columns
var dataColumn = 2;
var dataRow = 2;
var targetColumn = 3;
var j = 0;
//outer loop iterates through sheets
for (var i = 0; i < sheetNames.length; i++){
//inner loop works across the columns in each sheet, and across the column on the overview
for(var k = 0; k < dataLength; k++){
viewSheet.getRange(j+3, targetColumn+k).setValue(ss.getSheetByName(sheetNames[i]).getRange(dataRow, dataColumn).getValue());
dataColumn = dataColumn + 2;
}
//increments row counter for next sheet input
j = j+1;
//resets for next sheet
dataColumn = 2;
targetColumn = 3;
}
}
/*return sheetnames as array*/
function getSheetNames(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetArray = ss.getSheets();
var sheetNameArray = [];
for(var i = 0; i<sheetArray.length; i++){
sheetNameArray.push(sheetArray[i].getSheetName());
}
return sheetNameArray;
}

Resources