I need to figure out what to add to my script to add new data to the end of my sheet without overwriting the existing data. I'm a total beginner and have researched this, but can't seem to put the code together. Here is my script:
function myFunction() {
var url = "xxxxxxxx"
var response = UrlFetchApp.fetch(url)
var data = response.getContentText()
var result = JSON.parse(data)
var sheet = SpreadsheetApp.getActiveSheet()
sheet.clear()
var headerRow = ['Title','Brand','UPC','In Stock','Stock Level','Price','Seller','Next Day','Ship to Home', 'Link']
sheet.appendRow(headerRow)
for(var i=0; i<result.category_results.length; i++){
var row = [result.category_results[i].product.title, result.category_results[i].product.brand, result.category_results[i].product.upc,result.category_results[i].inventory.in_stock,
result.category_results[i].inventory.stock_level, result.category_results[i].offers.primary.price, result.category_results[i].offers.primary.seller_name,
result.category_results[i].fulfillment.next_day_shipping_eligible, result.category_results[i].fulfillment.ship_to_home, result.category_results[i].product.link]
sheet.appendRow(row)
}
}
Modification points:
In your script, the sheet is cleared every run by sheet.clear(). By this, the existing values are always deleted, and the sheet is overwritten by the new values. I think that this is the reason of your issue.
In your script, appendRow is used in a loop. In this case, the process cost will be high.
In order to append the new values to the sheet, I would like to propose the following flow.
Retrieve values. (This is your script.)
Check whether there are the existing values in the sheet.
Create an array for putting the values to the sheet.
Put the values using the array.
In this case, setValues is used instead of appendRow.
When above points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
// 1. Retrieve values. (This is your script.)
var url = "xxxxxxxx";
var response = UrlFetchApp.fetch(url);
var data = response.getContentText();
var result = JSON.parse(data);
// 2. Check whether there are the existing values in the sheet.
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
if (lastRow == 0) {
var headerRow = ['Title','Brand','UPC','In Stock','Stock Level','Price','Seller','Next Day','Ship to Home', 'Link'];
sheet.appendRow(headerRow);
}
// 3. Create an array for putting the values to the sheet.
var values = []
for(var i=0; i<result.category_results.length; i++){
var row = [result.category_results[i].product.title, result.category_results[i].product.brand, result.category_results[i].product.upc,result.category_results[i].inventory.in_stock,
result.category_results[i].inventory.stock_level, result.category_results[i].offers.primary.price, result.category_results[i].offers.primary.seller_name,
result.category_results[i].fulfillment.next_day_shipping_eligible, result.category_results[i].fulfillment.ship_to_home, result.category_results[i].product.link];
values.push(row);
}
// 4. Put the values using the array.
sheet.getRange(lastRow + 1, 1, values.length, values[0].length).setValues(values);
}
Note:
In this modified script, it supposes that your values can be retrieved with row. Please be careful this.
References:
setValues(values)
Benchmark: Reading and Writing Spreadsheet using Google Apps Script
Related
I am trying to copy data from 1 spreadsheet to another, I have successfully implemented something i found online that works with a specific range
function cloneGoogleSheet() {
// source doc
var sss = SpreadsheetApp.openById("spreadsheetkey1");
// source sheet
var ss = sss.getSheetByName('_tab_name_source');
// Get full range of data
var SRange = ss.getRange(7,3,5,1);
// get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
// get the data values in range
var SData = SRange.getValues();
// target spreadsheet
var tss = SpreadsheetApp.openById("spreadsheetkey2");
// target sheet
var ts = tss.getSheetByName('tab_name_destination');
// Clear the Google Sheet before copy
//ts.clear({contentsOnly: true});
// set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
};
The above piece coding work perfectly however I need to copy 18 different ranges that i cant just merge into 1 range. I considered the option of using the above however "multiplying" it 18 times for each range that however seems like a very inelegant solution.
I found a working solution that works if it stays within the same spreadsheet since it uses copyto instead of get/set values. The values part works perfectly since it doesnt mess with merge cells formatting. I have been struggling past 2-3 hours in merging the below-working code with elements from the first code to make a working script.
function test () {
try {
var spread = SpreadsheetApp.openById("spreadsheetkey");
var sheet = spread.getSheetByName("tab_name_source");
var rlist = sheet.getRangeList(["c7:c11", "g7:g11", "k7:k11"]);
sheet = spread.getSheetByName("tab_name_destination");
for( var i=0; i<rlist.getRanges().length; i++ ) {
var r1 = rlist.getRanges()[i];
var r2 = sheet.getRange(r1.getA1Notation());
r1.copyto(r2);
}
}
catch(err) {
Logger.log(err);
}
}
I tried initially to adapt the 2nd piece of coding to using setvalues however i had not been able to succesfully implement the part of getvalues within the scope of this code. I figured once I got this piece of code working with get and set values instead of Copyto i would only need to add the spreadsheetid of the other spreadsheet to get the final result
Try this:
function myFunction() {
var sourceSS = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = sourceSS.getSheetByName("sheetname");
var targetSS = SpreadsheetApp.openById("spreadsheet id here");
var targetSheet = targetSS.getSheetByName("Sheet1");
var ranges = ["C7:C11", "G7:G11", "K7:K11"];
ranges.forEach(range => {
var data = sourceSheet.getRange(range).getValues();
targetSheet.getRange(range).setValues(data);
})
}
Source sheet:
Destination sheet:
References:
setValues()
getValues()
Hi I'm using this code to loop trough another google worksheet find in column 'B' the id number 'idNum' once the id number is found the script replaces the whole row with new data but it seem to be taking a long time before the following script get triggered is there a way to make it faster to loop though or to make the next script trigger faster.
here's my code Thanks
function editRow(){
var mainsheet = ('10_XEaQiR71----- Sheet ID ----uOhi9VVtk5FI')
var tsheet = SpreadsheetApp.openById(mainsheet).getSheetByName('Data')
var targetSheet1 = tsheet.getDataRange().getValues()
var sheet = SpreadsheetApp.getActive();
var sourceData = sheet.getSheetByName('Data Input').getRange('A2:IB2').getValues()[0];
var idNum = sheet.getSheetByName('Data Input').getRange ("B2").getValue();
var copyFrom = sheet.getSheetByName('Data Input').getRange('A2:IB2')
var data = copyFrom.getValues()
for(var i = 0; i<targetSheet1.length;i++){
if(targetSheet1[i][1] == idNum){
var row = i=i+1
tsheet.getRange('A'+row+':IB'+row).setValues(data);
break;
}
}
next script
}
I believe your goal as follows.
You want to reduce the process cost of your script in your question.
Issue and workaround:
In your script, the values are retrieved from getRange("B2") and getRange('A2:IB2'). In this case, I think that you can retrieve them from getRange('A2:IB2').
When you are using V8 runtime, the process cost of for loop is almost the same with others. Ref So in this case, I would like to propose to use TextFinder instead of the for loop. Because I thought that TextFinder is run in the internal server and by this, the search process might be able to be reduced a little. But I'm not sure about your actual situation. So I'm not sure whether this is the correct direction for achieving your issue. So, please test the following script.
When your script is modified, it becomes as follows.
Modified script:
function editRow() {
var mainsheet = '10_XEaQiR71----- Sheet ID ----uOhi9VVtk5FI';
var sheet = SpreadsheetApp.getActive();
var data = sheet.getSheetByName('Data Input').getRange('A2:IB2').getValues();
var idNum = data[0][1];
var tsheet = SpreadsheetApp.openById(mainsheet).getSheetByName('Data');
var row = tsheet.getRange("B1:B" + tsheet.getLastRow()).createTextFinder(idNum).findNext().getRow();
tsheet.getRange(row, 1, 1, data[0].length).setValues(data);
// next script
}
Reference:
Class TextFinder
I have an html form where the client's data is inserted in and it appends row with the values on to a google sheet.
In the form, there's a field that searches and returns the clients data when searching for a specific value (id number).
function getID(IDsearch){
var ws = SpreadsheetApp.getActiveSheet();
var data = ws.getRange(3, 1, ws.getLastRow(), 36).getValues();
var dataInput = data.map(function(r){return r[7];});
var position = dataInput.indexOf(IDsearch);
var dataArray = ws.getRange(position+3, 1, 1, 36).getValues();
if(position > -1){
return dataArray;
} else {
return position;
}
}
After this runs, all the input fields in the form are populated with the data from that row.
I need to edit the values in the form and when submit it should overwrite/update the existing row with that id number.
In google sheets documentation, I've found the spreadsheets.values.update method, but I cannot figure this out. I'm pretty new in this and any help would be appreciated.
Thanks everyone!
You want to achieve the following flow.
Input "ID" to id="insertID" and click "Search by ID".
Show the values from Spreadsheet by searching "ID".
Edit the values of id="name" and id="ID".
When "Save data" is clicked, you want to update the values on the Spreadsheet.
From your replying, shared Spreadsheet and script, I could understand like above. If my understanding is correct, how about ths following modification? Please think of this as just one of several possible answers.
Modification points:
In your case, processForm at Google Apps Script side is required to be modified.
Search the row using formObject and overwrite the values of cells.
Modified script:
When your script is modified, please modify processForm at Google Apps Script side as follows. I remove the Spreadsheet ID from the URL. So please set it, before you test the script.
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/###/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
// I added and modified below script.
var ranges = ws.getRange(4, 2, ws.getLastRow() - 3, 1).createTextFinder(formObject.ID).findAll();
if (ranges.length > 0) {
for (var i = 0; i < ranges.length; i++) {
ranges[i].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);
}
} else {
ws.appendRow([formObject.name, formObject.ID]);
}
}
In this modification, when the same IDs are existing, all rows of the same IDs are overwritten. For example, if you want to modify the 1st one, please modify to ranges[0].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);.
Reference:
Class TextFinder
Try this:
function getID(IDsearch){
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();//dont know what the sheet is
var rg=sh.getRange(3,1,sh.getLastRow()-2,36);
var data=rg.getValues();
var idA=sh.getRange(3,8,sh.getLastRow()-2,1).getValues().map(function(r){return r[0];});//it looked like column 8 was your id column
var idx=idA.indexOf(IDsearch);
if(idx>-1) {
return ws.getRange(pos + 3,1,1,36).getValues()[0];//flattened the row to a 1d array
}else{
return idx;
}
}
#dianadfonseca, as #Tanaike points out, without more detail about your data structure, people will be speculating in order to answer your question. As I will be...
Please read the following answer, and tailor it to your needs if it works for you.
Example:
function getRow(id){
var ws = SpreadsheetApp.getActiveSheet();
// Number of headers to skip
var numHeaders = 2;
// the starting row
var startRow = numHeaders + 1;
// The column where the IDs are is known
var idCol = 8;
// The number of rows with data not headers
var numRows = ws.getDataRange().getLastRow() - numHeaders;
// An array with the ids to find a match in
// getRange() returns a 2D array, so you can transpose it to flatten it
var ids = ws.getRange(startRow,idCol,numRows).getValues();
ids = transpose(ids)[0];
// Get the index where id matches in ids
var row = ids.indexOf(id);
// If there's a match
if(row > -1){
// Correct row indexing
row = row + startRow;
}
return row;
}
function updateRow(row,data){
var ws = SpreadsheetApp.getActiveSheet();
// The column for each property is known
var propertyOneCol = 1;
// Update property using setValue()
ws.getRange(row,propertyOneCol).setValue(data.propertyOne);
// And so on...
}
// Transpose to avoid looping through the array
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
You can take a look the spreadsheet used for this example here with its bound script to play around.
Here is the function I used for testing
function test(){
// You are receiving this from your form
var data = {"propertyOne":"Juan","propertyTwo":20, "id":123467};
var id = data.id;
updateRow(getRow(id),data);
}
I am using the following script to import data from another Google Sheet but it doesn´t bring in the formula I need with it.
I have tried ImportRange but that seems to just sync the two sheets and I need to delete the data in the original sheet (Sheet 1) but that also deletes it in the sheet I bought in to (Master Sheet).
Is there another way to accomplish this?
function Copy() {
var sss = SpreadsheetApp.openById('Sheet 1 ID');
var ss = sss.getSheetByName('results');
var range = ss.getRange('2:688');
var data = range.getValues();
var tss = SpreadsheetApp.openById('Master Sheet ID');
var ts = tss.getSheetByName('results');
ts.getRange(ts.getLastRow() + 1, 1, data.length, data[0].length).setValues(
data
);
var sheet = SpreadsheetApp.openById('Sheet 1 ID').getSheetByName('Roger');
ss.getRange('2:688').clearContent();
}
Issue:
Formulas are not retrieved with getValues()
Possible Solutions:
Use range#getFormulas and range#getValues and mix those two arrays to create a array of formulas and values to setValues() later.
Use Advanced Google Services to access Sheets API to directly get the mix.
Sample Script Snippets:
var data = range.getValues();
data = range.getFormulas().map(function(e, i) {//i=index of row(e)
return e.map(function(f, j) {//j = index of column(f)
return f === "" ? data[i][j] : f;
});
});
or
var req = {
ranges: 'results!2:688',
valueRenderOption: 'FORMULA', //get formulas with values
};
var r = Sheets.Spreadsheets.Values.batchGet('Sheet 1 ID', req);
data = r.valueRanges[0].values;
References:
getFormulas
EnablingAdvancedServices
batchGet
In Google Spreadsheet I would like to take only the values from a complete list on one spreadsheet and append it to the bottom of a list on another spreadsheet. My trouble is that using the the copyValuesToRange() function errors the following:
Target sheet and source range must be on the same spreadsheet.
Here's my current code:
function transferList() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById("0ABCD");
var target_sheet = target.getSheetByName("RFPData");
var sheet = source.getSheetByName("RFP List");
var sheet_last_row = sheet.getLastRow() + 1;
var source_range = sheet.getRange("A2:I"+sheet_last_row);
var sWidth=source_range.getWidth() + 1;
var sHeight=source_range.getHeight() + 1;
var last_row=target_sheet.getLastRow();
source_range.copyValuesToRange(target_sheet , 1, sWidth,
last_row + 1, last_row + sHeight );
}
Any idea how I can get this to work?
As you've found, copyValuesToRange() is a Range method that affects a Sheet Object that is in the same Spreadsheet Object as the Range. There isn't an atomic method that will copy a range of values to another Spreadsheet, but there are a number of ways you could do it.
Here's one way.
From the source sheet, get all the data in one operation, by selecting the complete range of data using getDataRange() and then grabbing all values into a javascript array with getValues().
To ignore the first row of headers, use the javascript array method splice().
Locate your destination, which is on the target sheet, starting after the last row of data that's currently there, using getLastRow().
Write the source data (without the headers) to the destination sheet starting at the next row, using setValues().
Script:
function transferList() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RFP List");
var sourceData = sourceSheet.getDataRange().getValues();
sourceData.splice(0,1); // Remove header
var targetSS = SpreadsheetApp.openById("0ABCD").getSheetByName("RFPData");
var targetRangeTop = targetSS.getLastRow(); // Get # rows currently in target
targetSS.getRange(targetRangeTop+1,1,sourceData.length,sourceData[0].length).setValues(sourceData);
}
For some historic dashboard I created by importing and appending data, I use an add-on called Sheetgo. Save me programing time and help me with traceability issues.