sheets.properties to get specific sheetIDs rowCount - json

I need to copy data from 1 sheetId to another sheetId using
https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#copypasterequest
But to not over write the data in the destination sheet I need to know the rowCount, to get rowCount I use
https://developers.google.com/sheets/api/samples/sheet#sheetid
In this request you need to specify destination startRowIndex, there I need to know the amount of rows in the current sheet data is supposed to be pasted to and just +1 it.
{
"requests": [
{
"copyPaste": {
"source": {
"sheetId": 123,
"startRowIndex": 0,
"startColumnIndex": 0,
"endRowIndex": 2000,
"endColumnIndex": 5
},
"destination": {
"sheetId": 456,
"startRowIndex": 0,
"startColumnIndex": 0,
"endRowIndex": 2000,
"endColumnIndex": 5
},
"pasteType": "PASTE_NORMAL",
"pasteOrientation": "NORMAL"
}
}
But the Gsheet I'm working in has many sheets inside it and new ones is being added monthly, so is there any way to pinpoint
GET https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId?&fields=sheets.properties
to just get information from a specific sheetId?
I know I can do a batchupdate append to the other sheet but then I would have to read the data first, I wanted to see if I can just copy data from 1 sheet to another and not have it over write the old data

Related

How can I query Google APIs using fetch/XHR calls in a Google Chrome extension?

I am developing a Google Chrome extension that interacts with Google Sheets. I am already able to retrieve an OAuth 2.0 token by letting my user sign into their Google account, and this token allows me to access the Google Sheets API. In particular, I can succesfully reproduce the code user Parth Kapadia provides in their Stackoverflow answer here. This code allows me to create new Google Sheet file in my user's drive. However, I am unable to access any of the other functions of the Sheets API. In particular, the following code, which tries to change data in a spreadsheet,
data = {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + TOKEN
},
body: JSON.stringify({
requests: [{
repeatCell: {
range: {
startColumnIndex: 0,
endColumnIndex: 1,
startRowIndex: 0,
endRowIndex: 1,
sheetId: spreadsheetId
},
cell: {
userEnteredValue: {
"numberValue": 10
},
},
fields: "\*"
}
}]
}
fetch("https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/batchUpdate", data)
where TOKEN is the token I have retrieved and spreadsheetId is the id of the spreadsheet in question, returns the error "Failed to load resource: the server responded with a status of 404 ()". I took this code from this blog article.
I have also tried accessing other Sheets API commands, for example, values.get, through the url
const url = "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + "/values/A1:B2"
but this also returns an error (though apparently of a different nature; this is the error I get for values.get, and this is the error I get for batchUpdate). What is going on here? Essentially, I am asking if anyone has figured out how to successfully access the full Google Sheets API from a Chrome Extension, now that Google enforces Manifest v3 and the security policies coming with it. It seems that user Parth Kapadia figured out how to do it (as they mentions in their Stackoverflow post linked above), but they only share one piece of code, for the createSheet method, and I couldn't make any other methods work.
Modification points:
In your script, a spreadsheet ID is used for both spreadsheet ID and sheet ID.
About sheet ID, you can see it at the official document.
The endpoint is not correct.
data is not enclosed.
When these points are reflected in your script, how about the following modification?
Modified script:
const TOKEN = "###"; // Please set your access token.
const spreadsheetId = "###"; // Please set your spreadsheet ID.
const sheetId = "###"; // Please set your sheet ID.
const data = {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + TOKEN
},
body: JSON.stringify({
requests: [{
repeatCell: {
range: {
startColumnIndex: 0,
endColumnIndex: 1,
startRowIndex: 0,
endRowIndex: 1,
sheetId: sheetId
},
cell: { userEnteredValue: { numberValue: 10 } },
fields: "*"
}
}]
})
};
fetch("https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheetId + ":batchUpdate", data);
When this script is run, a value of 10 is put into a cell "A1" of sheetId in spreadsheetId.
Note:
This answer supposes that your access token can get and put values for Spreadsheet using Sheets API. Please be careful about this.
References:
Google Sheets API Overview
Method: spreadsheets.batchUpdate

how to map values to its corresponding row name

There is a collection of data which needs to be shown in the spreadsheet. I mean data will have values for each row(in this case Housing, CapitalRaised, SizePerSquare etc). How to plot below data in the spreadsheet in following format?
the data comes in this format
[
{
"Housing": "Before housing price",
"Price": 5,
"Rate": 0.75
},
{
"CapitalRaised": 5000,
"SizePerSquare": 12,
"Price": null,
"RatePerSquare": 1.25
},
{
"CapitalRaised": 6000,
"SizePerSquare": 24,
"Price": null,
"RatePerSquare": 1
},
{
"CapitalRaised": 7000,
"SizePerSquare": 24,
"Price": null,
"RatePerSquare": 0.75,
}
]
Here is the code
function plotData() {
var data =[
{
"Housing": "Before Capital Raised",
"Price": 5,
"Rate": 0.75
},
{
"CapitalRaised": 5000,
"SizePerSquare": 12,
"Price": null,
"RatePerSquare": 1.25
},
{
"CapitalRaised": 6000,
"SizePerSquare": 24,
"Price": null,
"RatePerSquare": 1
},
{
"AmountRaised": 7000,
"SizePerSquare": 24,
"Price": null,
"RatePerSquare": 0.75,
}
]
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "PlotData2";
var sheet = activeSheet.getSheetByName(sheetname);
var startRow = 4;
var range = "'" + sheetname + "'!B" + startRow;
}
Here is the link to spreadsheet
https://docs.google.com/spreadsheets/d/1tLNZv4F4lpBAnmHN5H0pBiirW4MVIfTexll9jPA03hI/edit#gid=1286090443
You want to achieve the following situation using Google Apps Script.
From:
var data = [
{"Housing":"Before housing price","Price":5,"Rate":0.75},
{"CapitalRaised":5000,"SizePerSquare":12,"Price":null,"RatePerSquare":1.25},
{"CapitalRaised":6000,"SizePerSquare":24,"Price":null,"RatePerSquare":1},
{"CapitalRaised":7000,"SizePerSquare":24,"Price":null,"RatePerSquare":0.75}
];
To:
The header titles of rows are constant.
If my understanding is correct, how about this answer? In this answer, from your question, I thought that the header titles of rows are constant. I used this situation.
Sample script:
Before you use the following scripts, please enable Sheets API at Advanced Google services. When the all column length of the array is not the same, the method of Spreadsheets.Values.update is easy to put the array to Spreadsheet. So I used Sheets API.
function plotData() {
var data = [
{"Housing":"Before housing price","Price":5,"Rate":0.75},
{"CapitalRaised":5000,"SizePerSquare":12,"Price":null,"RatePerSquare":1.25},
{"CapitalRaised":6000,"SizePerSquare":24,"Price":null,"RatePerSquare":1},
{"CapitalRaised":7000,"SizePerSquare":24,"Price":null,"RatePerSquare":0.75}
];
// Convert "data" to an array for putting to Spreadsheet.
var rowHeaders = ["Housing", "Price", "CapitalRaised", "RatePerSquare", "SizePerSquare"];
var values = data.reduce(function(ar, e, i) {
rowHeaders.forEach(function(g, n) {
if (!Array.isArray(ar[n])) ar[n] = [g];
ar[n][i + 1] = e[g];
});
return ar;
}, []);
// Put the converted array to Spreadsheet.
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "PlotData2";
var sheet = activeSheet.getSheetByName(sheetname);
var startRow = 4;
var range = "'" + sheetname + "'!B" + startRow;
Sheets.Spreadsheets.Values.update({values: values}, activeSheet.getId(), range, {valueInputOption: "USER_ENTERED"});
}
In above script, if there are the keys, which are not included in rowHeaders, in the keys of object of data, the values of the keys are not used. Please be careful this.
For example, Rate of the first element of data is not used.
Note:
In your data, it seems that the data of the data comes in this format is different from the data of Here is the code. "CapitalRaised": 7000, and "AmountRaised": 7000 are different. From your image of the expected result, I supposed that you want to use the data of the data comes in this format. If I misunderstood your goal, I apologize.
Reference:
Method: spreadsheets.values.update
If I misunderstood your question and this was not the direction you want, I apologize.

How to integrate a loop into my code that will apply my request to every filterViewId?

Currently encountering two problems with my code after executing:
API call to sheets.spreadsheets.batchUpdate failed with error: Invalid JSON payload received.
Unknown name "fields" at 'requests[0]': Cannot find field.
Invalid value at 'requests[0].update_filter_view.filter.filter_view_id' (TYPE_INT32), "*" (line 27, file "macros")
The first problem is that my request is not recognizing "fields" - I don't know why this is happening.
The second issue, and the main reason for posting this is that filterViewId is looking for an integer when all I have referenced was "*" as a method to update all filter views in the sheet. How can I integrate a loop into my code so that it Gets the first filterViewId and applies the request and then moves on to the next?
function UpdateFilterView() {
var sheets=SpreadsheetApp.getActiveSpreadsheet().getSheets();
for each (var dataSheet in sheets){
var lastRow = dataSheet.getLastRow();
var lastColumn = dataSheet.getLastColumn();
var sheetId = dataSheet.getSheetId();
var filterSettings = {
"filterViewId": "*",
"range":{
"sheetId": sheetId,
"startRowIndex": 0,
"endRowIndex": lastRow,
"startColumnIndex": 0,
"endColumnIndex": lastColumn
}
}
};
var requests = [{
"fields": "*",
"updateFilterView":{
"filter": filterSettings
}
}];
Sheets.Spreadsheets.batchUpdate({"requests":requests},sheetId);
}
Your request is not recognizing fields, because fields needs to go inside of "updateFilterView":{...} as you can see in the documentation.
If your filter Ids are incrementing with the sheet numbers (e.g. "filterViewId": 1 for the first sheet, "filterViewId": 2 for the second sheet etc.0, you can assign filterview to a counter variable which increments during each loop iteration.
Example:
var i=0;
for each (var dataSheet in sheets){
i++;
...
var filterSettings = {
"filterViewId": i,
...
Alternatively, you can also replace the for each loop by a for(var i=1; i<=sheet.length;i++) loop - then you iterate through sheets and filterview simultanously.

Last modified date in Google App Script GAS sheets

I am trying to get the last modified date of a sheet from a GAS add on which I am developing.
My current idea is to get the Drive revision list and then take the last value. This seems a bit overkill for just getting the last modified, I am also worried that this will break if the number of revisions exceeds 1000 as per this link suggests.
https://developers.google.com/drive/api/v3/reference/revisions/list
Ideally I would like to know the range which has changed too, but I do not think this is possible.
I cannot use the onEdit event because I would like to track edits made by users who have not installed the add-on.
var fileId = SpreadsheetApp.getActiveSpreadsheet().getId();
var revisions = Drive.Revisions.list(fileId);
var revisionLength = revisions.items.length;
if(revisionLength > 0){
var revision = revisions.items[revisionLength-1];
var date = new Date(revision.modifiedDate);
Logger.log(date.toString());
}
I believe you can do that as follow
var lastUpdated = DriveApp.getFileById(fileId).getLastUpdated();
See function reference
Given that you need users of your add-on to have access to revision information from non-add-on users, the Drive revision list is precisely what you need. Happily, you can get the content of revisions, so if you wish you can compute diffs. I don't know what your data looks like, so that might be easy or nigh-impossible.
Aside: to your point about more than 1000 revisions, if there are more than 1000 (or whatever your page size is) revisions, you'll get a nextPageToken like so:
{
"kind": "drive#revisionList",
"nextPageToken": "BHNMJKHJKHKVJHyugaiohasdzT1JyUmlQWG10RUJ1emx1S2xNDg4EgQzMzY1GAI=",
"revisions": [
...
]
}
If you see that you'll need to list revisions again, providing that token.
Anyway, when you list revisions, each revision will look something like this:
{
"kind": "drive#revision",
"etag": "\"som3-e-tAg\"",
"id": "3365",
"selfLink": "https://www.googleapis.com/drive/v2/files/dummydummydummy/revisions/3365",
"mimeType": "application/vnd.google-apps.spreadsheet",
"modifiedDate": "2018-10-19T19:05:41.762Z",
"published": false,
"exportLinks": {
"application/x-vnd.oasis.opendocument.spreadsheet": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=ods",
"text/tab-separated-values": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=tsv",
"application/pdf": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=pdf",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=xlsx",
"text/csv": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=csv",
"application/zip": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=zip",
"application/vnd.oasis.opendocument.spreadsheet": "https://docs.google.com/spreadsheets/export?id=dummydummydummy&revision=3365&exportFormat=ods"
},
"lastModifyingUserName": "Joe User",
"lastModifyingUser": {
"kind": "drive#user",
"displayName": "Joe User",
"picture": {
"url": "https://lh3.googleusercontent.com/-asdfsadf/AAAAAAAAAAI/AAAAAAAAFOk/OIPUYOIUGO/s64/photo.jpg"
},
"isAuthenticatedUser": true,
"permissionId": "123456789",
"emailAddress": "user#gmail.com"
}
}
Provided your data isn't insanely complex or large, you could fetch the target the text/csv export link for the revisions you wish to compare, and then do that comparison in Apps Script.
That might look something like:
var fileId = SpreadsheetApp.getActiveSpreadsheet().getId();
var revisions = Drive.Revisions.list(fileId);
var revisionLength = revisions.items.length;
if(revisionLength > 1) { // something to compare!
var revision = revisions.items[revisionLength-1];
var newContent = UrlFetchApp.fetch(revision.exportLinks["text/csv"]).getContent();
newContent = Utilities.parseCsv(newContent);
var oldRevision = revisions.items[revisionLength-2];
var oldContent = UrlFetchApp.fetch(oldRevision.exportLinks["text/csv"]).getContent();
oldContent = Utilities.parseCsv(oldContent);
# TODO check they're the same size!
# where do they differ?
for (var row = 0; row < newContent.length; row++) {
for (var col = 0; col < newContent[0].length; col++) {
if (newContent[row][col] != oldContent[row][col]) {
Logger.log('Change on row ' + (row + 1) + ' column ' + (col + 1));
}
}
# when did it change?
var date = new Date(revision.modifiedDate);
Logger.log(date.toString());
}

Error when creating pivot table

I am trying to create a pivot table using Google Apps Script. Once the script below runs, there is no output and an error is shown:
ReferenceError: "Sheets" is not defined. (line 50, file "Code")
function createPivotTable() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// The name of the sheet containing the data you want to put in a table.
var sheetName = "Data";
var pivotTableParams = {};
// The source indicates the range of data you want to put in the table.
// optional arguments: startRowIndex, startColumnIndex, endRowIndex, endColumnIndex
pivotTableParams.source = {
sheetId: ss.getSheetByName(sheetName).getSheetId()
};
// Group rows, the 'sourceColumnOffset' corresponds to the column number in the source range
// eg: 0 to group by the first column
pivotTableParams.rows = [{
sourceColumnOffset: 2,
sortOrder: "ASCENDING"
}];
// Defines how a value in a pivot table should be calculated.
pivotTableParams.values = [{
summarizeFunction: "COUNTA",
sourceColumnOffset: 2
}];
// Create a new sheet which will contain our Pivot Table
var pivotTableSheet = ss.insertSheet();
var pivotTableSheetId = pivotTableSheet.getSheetId();
// Add Pivot Table to new sheet
// Meaning we send an 'updateCells' request to the Sheets API
// Specifying via 'start' the sheet where we want to place our Pivot Table
// And in 'rows' the parameters of our Pivot Table
var request = {
"updateCells": {
"rows": {
"values": [{
"pivotTable": pivotTableParams
}]
},
"start": {
"sheetId": pivotTableSheetId
},
"fields": "pivotTable"
}
};
Sheets.Spreadsheets.batchUpdate({'requests': [request]}, ss.getId());
}
I just had the same issue. I was missing Google Sheets API
https://developers.google.com/sheets/api/quickstart/apps-script
After enabling, script finally worked.