App Script new Google Sheet creation issue - javascript

I am trying to write an App Script that takes string data from multiple different spreadsheets (completely separate documents) and puts them all in a new spreadsheet. When I run the logger, it shows me all the data I want. I want each piece of data to show up in Column A, but when I run my script, it only puts 1 data point in the spreadsheet instead of all of them. Can someone give me some guidance? Here is my code:
function pullTogether() {
var files = DriveApp.getFolderById('Folder ID').searchFiles('title != "nothing"');
const rangeName = 'Sheet1!B2:C';
while(files.hasNext()){
var xFile = files.next();
var name = xFile.getId();
const values = Sheets.Spreadsheets.Values.get(name, rangeName).values;
for (const row in values) {
var a1 = (values[row][0]);
Logger.log(a1);
var ss = SpreadsheetApp.openById("ID of new spreadsheet"); //I have the real ID in my code
var cell = ss.getRange("A2");
cell.setValue(a1);
}
}
}

I believe your goal is as follows.
You want to retrieve the values from the column "B" of each Spreadsheet under the specific folder.
You want to put the retrieved values to the column "A" of the destination sheet.
Modification points:
About but when I run my script, it only puts 1 data point in the spreadsheet instead of all of them., when I saw your script, the retrieved value is always put to the cell "A2" of the destination sheet. I think that this might be the reason for your issue.
In your script, I thought that when the following flow is used, the process cost will become low. By this flow, your issue can be also removed.
In your situation, even when Sheets API is not used, the script might work using getValues().
When these points are reflected in your script, it becomes as follows.
Modified script:
Please set the folder ID and the destination Spreadsheet ID.
function pullTogether() {
// Retrieve values from each Spreadsheet.
var values = [];
var files = DriveApp.getFolderById('Folder ID').searchFiles(`title != 'nothing' and mimeType='${MimeType.GOOGLE_SHEETS}'`);
var sheetName = 'Sheet1'
while (files.hasNext()) {
var xFile = files.next();
var sheet = SpreadsheetApp.open(xFile).getSheetByName(sheetName);
if (sheet) {
var v = sheet.getRange("B2:B" + sheet.getLastRow()).getValues();
values = [...values, ...v];
}
}
// Put values to the destination sheet.
var ss = SpreadsheetApp.openById("ID of new spreadsheet"); //I have the real ID in my code
var dstSheet = ss.getSheets()[0];
dstSheet.getRange(2, 1, values.length, values[0].length).setValues(values);
}
Note:
Although I'm not sure about your actual situation, when the above script didn't work by the large data, please modify as follows.
From
dstSheet.getRange(2, 1, values.length, values[0].length).setValues(values);
To
Sheets.Spreadsheets.Values.update({ values }, ss.getId(), `'${dstSheet.getSheetName()}'!A2`, { valueInputOption: "USER_ENTERED" });
References:
getValues()
setValues(values)

Related

Google App Script: The number of rows in the data doesn't match the number of rows in the range

I am writing a Google App Script, and I've gotten stuck. I am a beginner.
I have a .csv from our SQL server with 943 rows that is uploaded to my google drive. This script takes the contents of the .csv and moves it to a Google Sheet for use on my website.
It is working as long as the number of rows in the csv doesn't change. As items are added or removed from our web store, the script will not work and throws the error:
"Exception: The number of rows in the data does not match the number of rows in the range. The data has 943 but the range has 944."
function CSVCopyPaste(sourcelink,sourcerange,destilink,destisheet,destirange {
//Source link
var file = DriveApp.getFilesByName('CommercialAvailability.csv').next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
// Destination
var ss = SpreadsheetApp.openByUrl(destilink);
var sheet = ss.getSheetByName(destisheet);
// transfer to destination range
sheet.getRange(destirange).clearContent();
sheet.getRange(destirange).setValues(csvData);
}
The second function is called CommercialAvailability and it is the function I'm actually running to accomplish the result. It is:
function CommercialAvailability() {
SettlemyreCSVCopyPaste(
"https://drive.google.com/file/d/1-V040x0t6SWT14xx6N22MlVFhHnj9XE4",
"A3:C",
"https://docs.google.com/spreadsheets/d/1s8kzVxmJ6v3akpoZ8N2VoGMZ90U2kozlSXdRHUU2BAg/edit#gid=0",
"Commercial Availability",
"B6:D945"
)
}
Any help with this would be greatly appreciated!!
Thank you,
Alex
Alex, the issue is that your range is fixed (B6:D945) but the size of the data in the CSV is variable.
Try:
function CSVCopyPaste(sourcelink,sourcerange,destilink,destisheet,destirangestart) {
//Source link
var file = DriveApp.getFilesByName('CommercialAvailability.csv').next();
var csvData = Utilities.parseCsv(file.getBlob().getDataAsString());
//we need to check if the CSV is not empty
if (csvData.length > 0){
// Destination
var ss = SpreadsheetApp.openByUrl(destilink);
var sheet = ss.getSheetByName(destisheet);
var rangestart = sheet.getRange(destirangestart);
var writeRange = sheet.getRange(rangestart.getRow(),rangestart.getColumn(),csvData.length,csvData[0].length);
var clearRange = sheet.getRange(rangestart.getRow(),rangestart.getColumn(),sheet.getMaxRows()-rangestart.getRow(),csvData[0].length);
// transfer to destination range
clearRange.clearContent();
writeRange.setValues(csvData);
}
}
function CommercialAvailability() {
CSVCopyPaste(
"https://drive.google.com/file/d/1-V040x0t6SWT14xx6N22MlVFhHnj9XE4",
"A3:C",
"https://docs.google.com/spreadsheets/d/1s8kzVxmJ6v3akpoZ8N2VoGMZ90U2kozlSXdRHUU2BAg/edit#gid=0",
"Commercial Availability",
"B6"
)
}
Note that I haven't tested it. Also, you have unused arguments in CSVCopyPaste that you may want to get rid of.

Google Sheets, stack report from multiple workbooks

Goal: To stack data from 90+ google workbooks, all with the same sheet name, into the one master sheet for reporting
Info:
All worksheets have the same number of columns.
I have the following script but it does not run properly, I think the issue is with how I am caching / Pushing the data to the array before pasting to the output sheet.
I am trying to build an array then paste it in one go.
The tables I am stacking have 47 columns, unknown number of rows.
The part that opens the sheets is all working perfectly.
// Get the data from the worksheets
var indexsheet = SpreadsheetApp.getActive().getSheetByName("Index");
var outputsheet = SpreadsheetApp.getActive().getSheetByName("Output");
var response = SpreadsheetApp.getUi().prompt('Current Cycle', 'Enter Cycle Name Exactly in YY-MMM-Cycle# format', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL)
var CurrentCycleName = response.getResponseText()
// Assign datasets to variables
var indexdata = indexsheet.getDataRange().getValues();
// For each workbook in the index sheet, open it and copy the data to a cache
indexdata.forEach(function(row, r) {
try {
//open Entity specific workbook
var workbookid = indexsheet.getRange(r + 1, 7, 1, 1).getValues();
var Entityworkbook = SpreadsheetApp.openById(workbookid)
// Open workhseet
Entitysheet.getSheetByName(CurrentCycleName)
// Add PR Data to cache - stacking for all countrys
var PRDataCache = Entitysheet.getDataRange().push()
} catch {}
})
// Set the all values of the sheet at once
outputsheet.getRange(r + 1, 14).setValue('Issue Splitting Data')
Entitysheet.getRange(2, 1, PRDataCache.length || 1, 47).setValues(PRDataCache)
};
This is the index tab where we are getting the workbookid from to open each file
This is the output file, we are stacking all data from each country
I believe your goal is as follows.
You want to retrieve the Spreadsheet IDs from the column "G" of "Index" sheet.
You want to give the specific sheet name using a dialog.
You want to retrieve all values from the specification sheet in all Spreadsheets. In this case, you want to remove the header row.
You want to put the retrieved values on "Output" sheet.
In this case, how about the following sample script?
Sample script:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var indexsheet = ss.getSheetByName("Index");
var outputsheet = ss.getSheetByName("Output");
var response = SpreadsheetApp.getUi().prompt('Current Cycle', 'Enter Cycle Name Exactly in YY-MMM-Cycle# format', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
var CurrentCycleName = response.getResponseText();
var ids = indexsheet.getRange("G1:G" + indexsheet.getLastRow()).getValues();
var values = ids.reduce((ar, [id]) => {
try {
var [, ...values] = SpreadsheetApp.openById(id).getSheetByName(CurrentCycleName).getDataRange().getValues();
ar = [...ar, ...values];
} catch (e) {
console.log(`"${id}" was not found.`);
}
return ar;
}, []);
if (values.length == 0) return;
// If the number of columns is different in all Spreadsheets, please use the following script.
// var maxLen = Math.max(...values.map(r => r.length));
// values = values.map(r => r.length < maxLen ? [...r, ...Array(maxLen - r.length).fill("")] : r);
outputsheet.getRange(outputsheet.getLastRow() + 1, 1, values.length, values[1].length).setValues(values);
}
Note:
When the number of Spreadsheet IDs is large, the processing time might be over 6 minutes. I'm worried about this. At that time, how about separating the Spreadsheet IDs?
Reference:
reduce()

Need script to loop through stock ticker list, copy resulting output, and paste the output of multiple rows to separate sheet within workbook

My question is similar to Need script to loop through stock ticker list, copy resulting output, and paste output to separate sheet within workbook. However, instead of copying and pasting a single row (for each ticker) below the last non-empty row, I need to copy and paste 100 rows (for each ticker) below the last non-empty row.
I have three sheets named Tickers , Data, and Results within a single workbook.
If done manually, the job would be the following: Enter a stock symbol into cell A2 in the Data sheet. The sheet then retrieves the historical time series data from google finance, runs formulas and returns 100 rows and 7 columns of data (Ticker, Date, Open, High, Low, Close, Volume) into range A5:G254 within the same Data sheet. Copy the 100 rows of returned data and paste the data on the Results sheet below the last non-empty row. Then repeat the process with each ticker.
Request: Create a script to loop through a list of 50 stock symbols from the Ticker sheet (range B2:B51), paste 1 symbol at a time into cell A2 in the Data sheet, wait for google finance API to run, and then copy all the resulting rows generated in range A5:G254, and pasting those results into the Results sheet, below the data generated from previous ticker, until there is a "long format" table of time series data of each of the 50 tickers.
The issue with my current script is that it pastes only the first row of the wanted range A5:G254.
function getNewPrices() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const tickerSheet = ss.getSheetByName('Tickers');
const dataSheet = ss.getSheetByName('Data');
const resultsSheet = ss.getSheetByName('Results');
let data;
let myListOfTickers = tickerSheet.getRange('B2:B51').getValues().filter(String).sort();
myListOfTickers.forEach(ticker => {
dataSheet.getRange('A2').setValue(ticker[0]);
data = dataSheet.getRange('A5:G254').getValues()[0];
pasteData(resultsSheet, data);
});
};
function pasteData(resultsSheet,data){
let nextRow = resultsSheet.getLastRow() + 1;
data.forEach((datum,index) => {
resultsSheet.getRange(nextRow,index + 1,1,1).setValue(datum);
});
};
I'm not completely sure but I think this is what you want
function getNewPrices() {
const ss = SpreadsheetApp.getActive();
const tsh = ss.getSheetByName('Tickers');
let tvs = tsh.getRange('B2:B51').getValues().filter(String).sort();
const dsh = ss.getSheetByName('Data');
const rsh = ss.getSheetByName('Results');
dsh.getRange(2,1,tvs.length,tvs[0].length).setValues(tvs);
let dvs = dsh.getRange('A5:G254').getValues();
rsh.getRange(rsh.getLastRow() + 1, 1, dvs.length, dvs[0].length).setValues(dvs);
}
You can goto to Google Apps Script Reference and using the search box find any function that you don't understand. If it's a pure JavaScript function the go here
Problem solved. Here is the final code if anyone wants to use it later on. Thank you for the initial code Cooper.
function getNewPrices() {
const ss = SpreadsheetApp.getActive();
const tsh = ss.getSheetByName('Tickers');
let tvs = tsh.getRange('B2:B51').getValues().filter(String).sort();
const dsh = ss.getSheetByName('Data');
const rsh = ss.getSheetByName('Results');
tvs.forEach(ticker =>{
dsh.getRange('A2').setValue(ticker[0]);
let dvs = dsh.getRange('A5:G254').getValues();
rsh.getRange(rsh.getLastRow() + 1, 1, dvs.length, dvs[0].length).setValues(dvs);
});
}

How can I leave a blank space/column inside an appended row?

I'm trying to leave a blank column in between data of an appended row, so that I can add a VLOOKUP function, functionally I don't need to do this (I could just add the VLOOKUP to the end of the row), but aesthetically it would be better if I could. Is there a way to just skip a column when appending data into a row?
Explanation:
You can use two separate setValues statements to achieve your goal and paste the data right after the last row with content with getLastRow().
I have fully described each block of lines in the following script so I think it is straightforward to work with it.
I tried to create a generic code where you can select:
the column you want to separate the data: sep_col
the starting column you want to paste the data: start_col
the number of columns you want to have between the two different datasets: space_col
Code snippet:
function myFunction() {
// get spreadsheet details
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1'); // change that to the name of your sheet
// provide some data
const sep_col = 3; // column you want to separate the data
const data = ["d1","d2","d3","d5","d6"];
const data1 = data.slice(0,sep_col);
const data2 = data.slice(sep_col,data.length);
// get current last row of document
const Lrow = sh.getLastRow();
// paste the data to separate ranges
const start_col = 1;
const space_col = 1;
sh.getRange(Lrow+1,start_col, 1, data1.length).setValues([data1]);
sh.getRange(Lrow+1,start_col+data1.length + space_col, 1, data2.length).setValues([data2]);
}
JavaScript References:
Array.prototype.slice()
Sheet used for the code snippet:

how to insert multiple rows in a spreadsheet using google script

Is there any way i can insert multiple Rows into Google SpreadSheet without using any loops.
Need to do this task using google Apps Script only.
function testMultipleEntry(){
var sheet = SpreadsheetApp.openById(INSERT-SHEET-ID);
var mainSpreadSheet= sheet.getActiveSheet();
var fiveRows= mainSpreadSheet.getRange(2, 1, 5,mainSpreadSheet.getMaxColumns() );
var tempSheet= SpreadsheetApp.create("TestSheetAppend").getActiveSheet();
fiveRows.copyValuesToRange(tempSheet, 1, mainSpreadSheet.getMaxColumns(), 2, 5);//used the array[][]
}
last line is showing -- Service error: Spreadsheets
I'm still not clear on what it is you're looking for, but this code takes data from one sheet, and inserts it into another one:
function enterData(){
var ss = SpreadsheetApp.openById('SHEET-ID');
var mainSheet= ss.getActiveSheet();
var fiveRows= mainSheet.getRange(2, 1, 5,mainSheet.getMaxColumns());
var createSheet= ss.insertSheet("TestSheetAppend");//This line will fail if a sheet by this name exists.
var tempSheet = ss.getSheetByName('TestSheetAppend');
fiveRows.copyValuesToRange(tempSheet, 1, tempSheet.getMaxColumns(), 2, 5);//used the array[][]
}
If you're looking to send it to another sheet entirely, you can modify this code to do so.
I've spent some time looking into the official documentation on google app scripts, and based on that I can confirm you that there are many ways you can achieve this, one of which is explained below
getRange() + setValues()
Sample code
const startRowNumber = 1;
const starColumnNumber = 1;
const endRowNumber = dataToPut.length;
const endColumnNumber = dataToPut[0].length;
const range = sheet.getRange(startRowNumber, starColumnNumber, endRowNumber, endColumnNumber);
range.setValues(dataToPut);

Categories

Resources