Converting Sheet data to a new Sheet - google-apps-script

I'm trying to use Google Apps Script to communicate with Google Sheets to do the following:
We're trying to convert data from one Point of Sale system to a new one. In order to do this, I need to take certain columns of a sheet, manipulate them in various ways, and repopulate another sheet with the resulting data. I need to find products without a SKU number, and assign them a new one, starting at 10110 and incrementing from there.
function sku() {
// "From" Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("New POS Data");
// "To" Spreadsheet
// Spreadsheet key: the string at the end of the URL
var ssraw = SpreadsheetApp.openById("1BH-j4cOW9Ntg6FlPNXmNCUId_pm9BgyAh0cwrwB4z_A");
var sheetraw = ssraw.getSheetByName("Old POS Data");
var max = sheet.getLastRow();
// SKU / UPC
var range = sheetraw.getRange(2,18,max);
var data = range.getValues();
// Assign new sku if no old one
var skunum=[10110];
var newData = new Array();
for (var y = 0; y <= max; y++) {
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
else {newData.push(data[y]);}
}
sheet.getRange(2,3,max).setValues(newData);
}
This gives me the error "Incorrect range height, was 1 but should be 30 (line 26, file "SKU")"
If I remove the brackets around newData in the last line, I get "Cannot convert Array to Object[][]. (line 27, file "")"
This has been driving me mental, if anyone can offer help, I would be very grateful.

Even if you get a one row or one column vector with getData() you will get an Object[][].
when you do:
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
You check if [cellFromColumn] == "" which will evaluate to false as it's an array.
You then push the new/old sku number to a simple array which, for spreadsheets, is one row of columns.
Instead you want to push into the array a one element array containin the sku number like this:
newData.push(skunum);
...
newData.push([data[y]]);
This will create an array of rows, each row is an array with one element (one column)

Related

How do I return: a nested value, that's inside multiple indecis, within a JSON.parse API, into my google sheet cells?

I'm fetching data from this binance API(https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14).
I've, successfully, looped through the 'limit=14' parameter, which returns 0-13 indecis(or 14 indeces all together). These indeces contain various data on the pair specified in the 'symbol=ADAUSDT' parameter.
Now, theres 2 particular values I'm interested in: the high and the low of the day, which are in positions 2 and 3, respectively, in each index 0-13.
So, I've been able to log 0-13 results with the below script, but when I try to return the results to my sheet, it only populates the value in only one index, instead of 0-13.
How would I populate the results of my loop into the cells on my sheet?
function atrCalculation() {
var dailyHigh = UrlFetchApp.fetch("https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14");
var jsonHighPrice = JSON.parse(dailyHigh);
for (var i = 0; i < jsonHighPrice.length; i++) {
data = jsonHighPrice[i];
Logger.log(data[2]);
Return data[i][2];
function in cell
only one value produced
Logger.log result
Thanks for any help!
You can simply retrieve all the data in your sheet 'klines' this way
function myKlines(){
var url='https://api1.binance.com/api/v3/klines?symbol=ADAUSDT&interval=1d&limit=14'
var source = UrlFetchApp.fetch(url).getContentText()
var json = JSON.parse(source)
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('klines')
sh.getRange(1, 1, json.length, json[0].length).setValues(json);
}

How to separate column into two separate columns by condition App Script

I am trying to take the Data in the scan it columns and conditionally filter it into the commercial or manufacturing sheet.
I tried writing a formula as an if function basically saying if it equals "Company" put it in manufacturing column, if not(if the rest) then put into commercial column.
I tried coding it backend in app script, but had an issue grabbing the last row from scan it and correctly adding the item #, vendor, and quantity into the last row of either Commercial or Manufactured.
The scan it section is an importrange function so more data will be entered into it once the code is working correctly.
I ran into dead ends with both. This is obviously an advanced code and I only did a little bit of coding in college. Below is a script that I had been messing with trying to get it to filter the data properly, but I couldn't get it to run. Any help would be appreciated!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1')
//Get last rows for MFG
var mfgvalues = sheet.getRange(3, 5, sheet.getLastRow()).getValues();
//var mfglast = mfgvalues.filter(String).length;
//Get last rows for Comm
var commvalues = sheet.getRange(3, 1, sheet.getLastRow()).getValues();
//var commlast = commvalues.filter(String).length;
//Get last rows for Scann
var scanvalues = sheet.getRange(2, 12, sheet.getLastRow()).getValues();
//var scanlast = scanvalues.filter(String).length;
//Filter Accordingly
if (scanvalues == "IMMCO") {
var scanrange = sheet.getRange("L2:N").getLastRow().getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var mfgrow = sheet.getRange("E3:G").getLastRow();
scanlastrow.copyTo(mfgrow)
} else {
var scanrange = sheet.getRange("L:N").getLastRow.getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var commrow = sheets.getRange("A3:C").getLastrow()
scanlastrow.copyTo(commrow)
}
}
https://docs.google.com/spreadsheets/d/1D0FvVoTADi3t3ENPceB14QYYI4lNI6C3xj2OF-St7Is/edit?usp=sharing
GOOGLE SHEET OUTPUT WANTED
Option1:
Using FILTER() to filter your data set if vendor name is equal to "COMPANY" as mentioned in your description
Formula in Cell A3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)<>"COMPANY")
Formula in Cell E3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)="COMPANY")
Output:
Option2:
Using apps script to filter your data set.
Sample Code:
function filter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
//Get item count for Scann
var scanCnt = sheet.getRange('L3:L').getValues().flat().filter(String).length;
Logger.log(scanCnt);
//Get last rows for Comm
var commLastRow = sheet.getRange('A1:A').getValues().flat().filter(String).length;
Logger.log(commLastRow);
//Get last rows for MFG
var mfgLastRow = sheet.getRange('E1:E').getValues().flat().filter(String).length;
Logger.log(mfgLastRow);
//Get Scann data if item count is not zero
if(scanCnt){
var commItem = [];
var mfgItem = [];
var dataRange = sheet.getRange(3,12,scanCnt,3);
var data = dataRange.getDisplayValues();
//Loop all scann data and separate mfg with comm
Logger.log(data.length)
data.forEach(item => {
Logger.log(item);
if(item[1].toUpperCase() == "COMPANY"){
mfgItem.push(item);
}else{
commItem.push(item);
}
});
Logger.log(mfgItem);
Logger.log(commItem);
//Append comm items
sheet.getRange(commLastRow+1,1,commItem.length,commItem[0].length).setValues(commItem);
//Append mfg items
sheet.getRange(mfgLastRow+1,5,mfgItem.length,mfgItem[0].length).setValues(mfgItem);
//Optional: Clear content of scann column
dataRange.clearContent();
}
}
What it does?
Get the item count to filter in Scan it column by selecting the range L3:L. Get its value. Change 2-d array to 1-d array using array.flat(). Use array.filter() to remove empty values. Then get its length
Get the last row of Commercial(ColumnA) and Manufactured(ColumnE) column.
If item count obtained in step1 is not zero. Then get the data range and its value
Loop all data value (by row) one-by-one. Check if vendor index is equal to "COMPANY" then add it to mfgItem array. Else, add it to commItem array
Append mfgItem and commItem under Manufactured Column and Commercial Column
(Optional) Clear the data under Scan-it Column
Note:
You can check the execution log to further understand the procedure done. I included some debug logs in the sample code.
Output:

Trying to write a list of the named ranges in my Google Sheet to a separate sheet

I'm new to coding. I have a Google Sheet that includes 314 named range variables. I am trying to print a verticle list of all of the named ranges to a separate sheet in my workbook. The error I get is confusing. It reads
Exception: The number of rows in the data does not match the number of rows in the range. The data has 1 but the range has 314. (line 47, file "Code")
Here's my code. I am not sure what I'm missing?
function myFunction() {
//Declaring the Active Sheet
var mySheet = SpreadsheetApp.getActiveSheet();
//Declaring Array
var myArray = SpreadsheetApp.getActiveSpreadsheet().getNamedRanges();
//Clearing a range on the Google Sheet
mySheet.getRange('Named Ranges!A1:A314').clearContent();
//Printing Array to Google Sheet
mySheet.getRange('Named Ranges!A1:A314').setValues([myArray]);
}
The method getNamedRanges() returns you the range objects rather than their names and setValues only works if the dimensions of the values correspond to the dimension of the range
To retrieve the name ranges you need to iterate through all range objects and retrieve the name of each single range with getName()
[myArray] will have the content [[range1, range2, ...]] which will be interpreted as an nested array will multiple columns and only one row
To create an array with multiple columns and only one row you can do the following:
var myRanges = SpreadsheetApp.getActiveSpreadsheet().getNamedRanges();
Logger.log(myRanges);
var myArray = [];
for (var i = 0; i< myRanges.length; i++){
myArray[i] = [];
myArray[i].push(myRanges[i].getName());
}
Given that your sheet mySheet is always the active sheet, you can specify a different sheet name within getRange(). Instead specify either
SpreadsheetApp.getActiveSpreadsheet().getRange('Named Ranges!A1:A314')
or even better dynamically:
var myRangeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Named Ranges');
myRangeSheet.getRange(1,1, myArray.length, 1)
As the number of rows and columns in the data has to match the number of rows in the range, the latter approach the latter allows you to estimate the row number corresponding to the number of list entries dynamically, no matter what the number of the named ranges.
It is not necessary to clearContent() before overwriting eventual data with setValues
Sample modification of you code:
function myFunction() {
var myRanges = SpreadsheetApp.getActiveSpreadsheet().getNamedRanges();
var myArray = [];
for (var i = 0; i< myRanges.length; i++){
myArray[i] = [];
myArray[i].push(myRanges[i].getName());
}
var myRangeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Named Ranges');
myRangeSheet.getRange(1,1, myArray.length, 1).setValues(myArray);
}

Automatically add variables to array?

In a google script I have written something to check my monthly expenses, which are listed in a google sheet.
Based on words the script finds, every line gets a category tag. It works fine, but the number of words to search for is getting big. And the array is getting big too.
I have listed 6 pairs (words to find, tag to add) - but in real version I have as many as 35. How can I create the pairs, and load everything automatically in the array?
This is my script:
function myFunction() {
// check usual suspects
var A1 = ["CAFE", "HORECA"]
var A2 = ["ALBERT", "AH"]
var A3 = ["VOMAR","Vomar"]
var A4 = ["HEMA","HEMA"]
var A5 = ["KRUID","Drogist"]
var A6 = ["RESTA", "Horeca"]
// in Array
var expenses = [A1,A2,A3,A4,A5,A6]
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
for (i in expenses)
{for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
if(data[n][3].toString().toUpperCase().match(expenses[i][0])==expenses[i][0]){ data[n][4] = expenses[i][1]};
// if column D contains 'xyz' then set value in index [5] (is column E)
}
Logger.log(data)
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
}
I can propose you that:
function multiPass(){
var searchCriterions = [
["CAFE","HORECA" ],
["ALBERT", "AH"],
["VOMAR","Vomar"],
["HEMA","HEMA"]
];
var dico = {};
var patt = "";
for (var i in searchCriterions) {
dico[searchCriterions[i][0]] = searchCriterions[i][1];
patt += "("+searchCriterions[i][0]+")";
if((Number(i)+1)<searchCriterions.length){
patt += "|";
}
}
var re = new RegExp(patt,"");
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
Logger.log(re);
for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
// THAT'S NOT COLUMN "A", 3 --> "D"
var test = data[n][3].toString().toUpperCase().match(re);
Logger.log(test);
if(test!==null){
data[n][4] = dico[test[0]]
};
}
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
instead of using variable for your "pairs" prefer to use a big table (it's less painfull to write)
then transform your pairs in object to quickly access the second argument of the pair and create a big regexp that check at once all the keywords instead of parsing them one by one.
Now as we are using a big array as search criterions we can totally imagine that this big array is loaded instead of hard coding it. If you have a sheet where the data is you can change the code this way:
var searchCriterions = SpreadsheetApp.getActive().getRange("namedRange").getValues();

Find string and get its column

Let's say I have a lot of columns and one of them contains "impressions" string (on row 3). What I need to do is to:
1) Find the cell with "impressions" string
2) Get column number or i.e. "D"
3) Based on what I got paste a formula into i.e. D2 cell which gets AVERAGE from a range D4:D*last*
I couldn't find it anywhere so I have to ask here without any "sample" code, since I have no idea on how to achieve what I want. (3rd one is easy but I need to get that "D" first)
There's no way to search in Google Apps Script. Below is a function that will accomplish the first 2 parts for you (by iterating over every cell in row 3 and looking for "impressions"):
function findColumnNumber() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1'); // insert name of sheet here
var range = sheet.getDataRange(); // get the range representing the whole sheet
var width = range.getWidth();
// search every cell in row 3 from A3 to the last column
for (var i = 1; i <= width; i++) {
var data = range.getCell(3,i)
if (data == "impressions") {
return(i); // return the column number if we find it
}
}
return(-1); // return -1 if it doesn't exist
}
Hopefully this will allow you to accomplish what you need to do!
The indexOf method allows one to search for strings:
function findColumnNumber() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet() //whatever tab the code is run on
var data = sheet.getDataRange().getValues();
var header_row_num = 1; // TODO: change this to whichever row has the headers.
var header = data[header_row_num -1] //Remember JavaScript, like most programming languages starts counting (is indexed) at 0. For the value of header_row_num to work with a zero-index counting language like JavaScript, you need to subtract 1
//define the string you want to search for
var searchString = "impressions";
//find that string in the header and add 1 (since indexes start at zero)
var colNum = header.indexOf(searchString) + 1;
return(colNum);