Date format messed up while copying data from one spreadsheet to another using Google Sheets API batchUpdate - google-sheets-api

I am copying a dataset from one spreadsheet to another and all is fine except the dates.
In the source file the dates are like "2020-07-27", but after I run the script, the dates in the destination file are in completely different format like "Sun Jul 26 18:00:00 GMT-04:00 2020".
What should I do in order to copy the date as it is - YYYY-MM-DD?
My code:
function myFunction() {
var sheet_source_values = SpreadsheetApp.openById("1JfjXPPFj08p6cxjdsdcBhTMkl6yXLJkhASG0dv4").getSheetByName(Utilities.formatDate(now,"GMT+1", "dd.MM")).getRange('A:AD').getValues()
var sheet_destination = SpreadsheetApp.openById("GTjEfvjoTJ7U7ZXwYUEnSkKtfudXZuCP0dyq").getSheetByName("Updated_sheet")
var request = {
'responseValueRenderOption' : 'UNFORMATTED_VALUE',
'valueInputOption': 'RAW',
'responseDateTimeRenderOption' : 'SERIAL_NUMBER',
'data': [
{
'range': "'Updated_sheet'!" + sheet_destination.getRange(2,1,sheet_source_values.length,sheet_source_values[0].length).getA1Notation(),
'majorDimension': 'ROWS',
'values': sheet_source_values
}
]
};
Sheets.Spreadsheets.Values.batchUpdate(request, "GTjEfvjoTJ7U7ZXwYUEnSkKtfudXZuCP0dyq");
}
I tried changing "responseValueRenderOption" and "responseDateTimeRenderOption" but could find solution :(

The problem here is not with the Sheets API, but with the way you are retrieving the values from the source spreadsheet.
According to the getValues method documentation:
getValues - Returns a two-dimensional array of values, indexed by row, then by column. The values may be of type Number, Boolean, Date, or String, depending on the value of the cell.
In this way, the values will be retrieved as a Date type, but this type is the Google default one, hence the results you are getting on the destination sheet.
In order to fix this, I suggest you use getDisplayValues instead as this will return the displayed values from the source sheet. As for the Sheets API request, you can simply keep the 'valueInputOption': 'RAW' option only.
Modified sheet_source_values
var sheet_source_values = SpreadsheetApp.openById("1bGCXCUe6cgyLQRUQrOIAT2BruBH95ybAX7iG_pyk4Q0").getSheetByName("Sheet1").getRange('A1:A4').getDisplayValues();
Modified Sheets API request
var request = {
'valueInputOption': 'RAW',
'data': [{
'range': "'Updated_sheet'!" + sheet_destination.getRange(2, 1, sheet_source_values.length, sheet_source_values[0].length).getA1Notation(),
'majorDimension': 'ROWS',
'values': sheet_source_values
}]
};
Reference
Google Apps Script Range Class - getDisplayValues();
Google Apps Script Range Class - getValues().

Related

Google Sheets - Parse unsorted comma separated values from one column, into separate columns. The values are not always in the same order

Three example rows from that column are shown below.
{'gender': 'Female', 'document_type': 'driving_licence', 'date_of_expiry': '2024-03-03', 'issuing_country': 'GBR'}
{'nationality': 'DEU', 'document_type': 'national_identity_card', 'date_of_expiry': '2020-11-19', 'issuing_country': 'DEU'}
{'gender': 'Female', 'nationality': 'FRA', 'document_type': 'passport', 'date_of_expiry': '2024-01-22', 'issuing_country': 'FRA'}
My desired outcome would be:
gender | document_type | document_type | date_of_expiry | issuing country | nationality | national_identity_card |
e.g.
Female | driving_licence | 2024-03-03 | GBR | NULL | NULL
NULL | national_identity_card | 2020-11-19 | DEU | DEU
.
.
.
Any help would be great :)
Indeed it looks like JSON. You could replace all the ' with " and paste the records here: https://codebeautify.org/jsonviewer
The complete string for the examples you provided would be:
{
"example": [
{
"gender": "Female",
"document_type": "driving_licence",
"date_of_expiry": "2024-03-03",
"issuing_country": "GBR"
},
{
"nationality": "DEU",
"document_type": "national_identity_card",
"date_of_expiry": "2020-11-19",
"issuing_country": "DEU"
},
{
"gender": "Female",
"nationality": "FRA",
"document_type": "passport",
"date_of_expiry": "2024-01-22",
"issuing_country": "FRA"
}
]
}
After that, clicking the button JSON to CSV generates the values sorted by columns like this:
gender,document_type,date_of_expiry,issuing_country
Female,driving_licence,2024-03-03,GBR
,national_identity_card,2020-11-19,DEU
Female,passport,2024-01-22,FRA
While the answer from #jota seems to have solved your problem, I have an alternative solution for that works mostly automatically, though it depends if you always receive the data as objects, ideally in an array.
A potential Apps Script solution
First you need to create a Google Sheet and fill in the headers. The text must match exactly the title of the property titles you are receiving. For example, document_type not Document Type.
Then open the Script Editor by clicking on the 'Tools' menu, then select 'Script editor...'.
Replace the code with the following:
function addToSheet() {
// Ideally this data gets created automatically but here is the example you gave.
let example = [
{
gender: "Female",
document_type: "driving_licence",
date_of_expiry: "2024-03-03",
issuing_country: "GBR",
},
{
nationality: "DEU",
document_type: "national_identity_card",
date_of_expiry: "2020-11-19",
issuing_country: "DEU",
},
{
gender: "Female",
nationality: "FRA",
document_type: "passport",
date_of_expiry: "2024-01-22",
issuing_country: "FRA",
},
];
// Defining where to put the data
let ss = SpreadsheetApp.getActiveSpreadsheet(); // Spreadsheet the script is attached to
let sheet = ss.getSheetByName("Sheet1"); // Put the name of your sheet here
let sheetData = sheet.getDataRange().getValues(); // Gets all data from sheet.
// Take headers from data
let headers = sheetData.shift(); // removes first row, which is the headers, of data and assigns to variable
// For each entry, create an array, and fill it according to the header structure.
example.forEach((entry) => {
let newRow = []; // initializing new array
// build the new row according to the header structure.
headers.forEach(header => {
newRow.push(entry[header]); // add cell value to row, if not present in entry, will fill with undefined
})
sheet.appendRow(newRow); // add built row to sheet
});
}
I adapted the structure provided by #jota. What would be up to you is to adapt the data you are getting to be an array of objects. What I have defined as example, would be the necessary format.
Then if you run the code, it will append the rows in the right place.
References and explanation
SpreadsheetApp - the service within Apps Script that allows you to manipulate spreadsheets.
Spreadsheet - the spreadsheet object.
Sheet - the sheet object, in the example above, the sheet must be named "Sheet1" - though you can change that in your code to adapt to your needs, of course.
Range - The methods associated with ranges (selections etc).
Append Row - The method used to add the row at the end.
getDataRange - The method used to select the range containing all the data in the particular sheet. In this case, it is used to dynamically get the headers.
getValues - Used in conjunction with getDataRange to actually return the values. getDataRange only returns the range object which contains the values, but has a lot more to it too. With getValues you get a simple two dimensional array.
The script gets the headers in an array, it uses the headers array to build a row for the sheet for each object defined in example, and appends each row to the sheet after its built.
This can be adapted to many situations, but the advantage it has, is that the object can have all or none of the fields, in any order, and it will update the spreadsheet correctly regardless. As mentioned previously, the only issue you may encounter, is getting the initial data into the right format.

Google Sheets API Node.js Append Overwrite

I have a dumb question. I have a script running on google sheets. Every week, I would like to run a script and replace the data on a specific sheets.
I tried to do it through insertDataOption = OVERWRITE, but it does not work.
When I read the documentation, here what is written:
OVERWRITE The new data overwrites existing data in the areas it is written. (Note: adding data to the end of the sheet will still insert new rows or columns so the data can be written.)
Do you have any idea what I do wrong?
You are using the spreadsheets.values.append endpoint. From the documentation:
Appends values to a spreadsheet. The input range is used to search for existing data and find a "table" within that range. Values will be appended to the next row of the table, starting with the first column of the table.
If what you want, instead of appending data is to replace data in a range of your sheet, you should instead be using the spreadsheets.values.update endpoint. For your case, it can be used as follows:
function insertData(auth) {
const sheets = google.sheets({version: 'v4', auth});
var request = {
spreadsheetId: '###',
range: 'A1:D48',
valueInputOption: 'RAW',
resource: {
values: [[getting_company_name, duration_event, current_date, getting_profesional_service]]
}
};
sheets.spreadsheets.values.update(request,
(err, res) => {
if (err) return console.log('The API returned an error: ' + err);
});
}
You can find more information on creating a node js application for Sheets here
#Frenchcooc
var request = {
// The ID of the spreadsheet to update.
spreadsheetId: '###',
range: 'A1:D48',
valueInputOption: 'RAW',
insertDataOption: 'OVERWRITE',
resource: {
values: [[getting_company_name, duration_event, current_date, getting_profesional_service]]
},
auth: authClient,
};

columnSummary is not added

I am trying to add columnSummary to my table using Handsontable. But it seems that the function does not fire. The stretchH value gets set and is set properly. But it does not react to the columnSummary option:
this.$refs.hot.hotInstance.updateSettings({stretchH: 'all',columnSummary: [
{
destinationRow: 0,
destinationColumn: 2,
reversedRowCoords: true,
type: 'custom',
customFunction: function(endpoint) {
console.log("TEST");
}
}]
}, false);
I have also tried with type:'sum' without any luck.
Thanks for all help and guidance!
columnSummary cannot be changed with updateSettings: GH #3597
You can set columnSummary settings at the initialization of Handsontable.
One workaround would be to somehow manage your own column summary, since Handsontable one could give you some headeache. So you may try to add one additional row to put your arithmetic in, but it is messy (it needs fixed rows number and does not work with filtering and sorting operations. Still, it could work well under some circumstances.
In my humble opinion though, a summary column has to be fully functionnal. We then need to set our summary row out of the table data. What comes to mind is to take the above mentioned additional row and take it away from the table data "area" but it would force us to make that out of the table row always looks like it still was in the table.
So I thought that instead of having a new line we could just have to add our column summary within column header:
Here is a working JSFiddle example.
Once the Handsontable table is rendered, we need to iterate through the columns and set our column summary right in the table cell HTML content:
for(var i=0;i<tableConfig.columns.length;i++) {
var columnHeader = document.querySelectorAll('.ht_clone_top th')[i];
if(columnHeader) { // Just to be sure column header exists
var summaryColumnHeader = document.createElement('div');
summaryColumnHeader.className = 'custom-column-summary';
columnHeader.appendChild( summaryColumnHeader );
}
}
Now that our placeholders are set, we have to update them with some arithmetic results:
var printedData = hotInstance.getData();
for(var i=0;i<tableConfig.columns.length;i++) {
var summaryColumnHeader = document.querySelectorAll('.ht_clone_top th')[i].querySelector('.custom-column-summary'); // Get back our column summary for each column
if(summaryColumnHeader) {
var res = 0;
printedData.forEach(function(row) { res += row[i] }); // Count all data that are stored under that column
summaryColumnHeader.innerText = '= '+ res;
}
}
This piece of code function may be called anytime it should be:
var hotInstance = new Handsontable(/* ... */);
setMySummaryHeaderCalc(); // When Handsontable table is printed
Handsontable.hooks.add('afterFilter', function(conditionsStack) { // When Handsontable table is filtered
setMySummaryHeaderCalc();
}, hotInstance);
Feel free to comment, I could improve my answer.

Find if a range exists in a spreadsheet

How can I list the names of the worksheets in a Google SpreadSheet? I am trying to find if a worksheet exists using DataFilters
This is my function
public bool RangeExists(string sheet, string range)
{
BatchGetValuesByDataFilterRequest r = new BatchGetValuesByDataFilterRequest();
DataFilter filter = new DataFilter();
filter.A1Range = range;
r.DataFilters = new List<DataFilter>() { filter };
var a = service.Spreadsheets.Values.BatchGetByDataFilter(r, sheet).Execute();
return a.ValueRange.Count>0;
}
This code throws this exception when I try to find if my spreadsheet has a sheet called "Sheet":
Google.Apis.Requests.RequestError
Invalid dataFilter[0]: Unable to parse range: Sheet!A:ZZ [400]
Errors [
Message[Invalid dataFilter[0]: Unable to parse range: Sheet!A:ZZ] Location[ - ] Reason[badRequest] Domain[global]
]
Thank you.
If you check REST Resource: spreadsheets you'll notice that there's a sheets property that should display all the sheets within a spreadsheet.
"sheets": [
{
object(Sheet)
}
]
So, what you can do is to make a call to spreadsheets.get. This will return that sheets object which you're looking for. You can use the Try-it from that link and indicate '*' in the "fields" parameter to return all properties (that includes the sheets).

How to get first row from Google Spreadsheets Data API

Here is an example: https://spreadsheets.google.com/feeds/list/1a2JzZzUjSIcpROgR5v_M-UmWyT-iokcegIxHJOopZWA/od6/public/full?alt=json
The returned JSON data doesn't contain the first row from the spreadsheet.
You can view the contents of the spreadsheet in HTML (https://docs.google.com/spreadsheets/d/1a2JzZzUjSIcpROgR5v_M-UmWyT-iokcegIxHJOopZWA/pubhtml) to verify that "first row" exists in the sheet.
How can I get the first row from the spreadsheet? There is a "openSearch$startIndex" = 1 in the returned JSON. Maybe if you could set this to 0, I could get the first row also.
1st Row - Cell feed
https://spreadsheets.google.com/feeds/cells/key/worksheetId/private/full?min-row=1&min-col=1&max-col=4
Docs: https://developers.google.com/google-apps/spreadsheets/#fetching_specific_rows_or_columns
Cell feed is better for almost everything. But append a data row is better in list feed, I think.
In C# you would do it like this:
var link = worksheet.Links.FindService(GDataSpreadsheetsNameTable.CellRel, null).HRef.ToString();
var cellQuery = new CellQuery(link)
{
MinimumRow = 1,
MaximumRow = 1,
MinimumColumn = 1
};
CellFeed header = spreadsheetService.Query(cellQuery);