How to get unique data of google sheets to json with appscript? - json

I'm getting values of the sheet in JSON format. My Sheet
I've added this code in appscript to get JSON:
var ss = SpreadsheetApp.openByUrl("Spreadsheet URL");
var sheet = ss.getSheetByName('Sheet1');
function doGet(e){
var action = e.parameter.action;
if(action == 'getItems'){
return getItems(e);
}
}
function getItems(e){
var records={};
var rows = sheet.getRange(2, 1, sheet.getLastRow() - 1,sheet.getLastColumn()).getValues();
data = [];
for (var r = 0, l = rows.length; r < l; r++) {
var row = rows[r],
record = {};
record['customerName'] = row[0];
record['docketNo']=row[1];
record['docketDate']=row[2];
record['destination']=row[3];
record['weight']=row[4];
data.push(record);
}
records = data;
var result=JSON.stringify(records);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
Current JSON data:
[
{
"customerName":"cash",
"docketNo":"d87976489",
"docketDate":"2021-08-14T18:30:00.000Z",
"destination":"kanpur",
"weight":1
},
{
"customerName":"cash",
"docketNo":"d87976480",
"docketDate":"2021-08-12T18:30:00.000Z",
"destination":"kanpur",
"weight":1
},
{
"customerName":"abc",
"docketNo":"d87976482",
"docketDate":"2021-09-12T18:30:00.000Z",
"destination":"mumbai",
"weight":2
}
]
I want this JSON data:
[
{
"customerName":"cash",
"docketNo":"d87976489","d87976480",
"docketDate":"2021-08-14T18:30:00.000Z","2021-08-12T18:30:00.000Z",
"destination":"kanpur","kanpur",
"weight":1,1
},
{
"customerName":"abc",
"docketNo":"d87976482",
"docketDate":"2021-09-12T18:30:00.000Z",
"destination":"mumbai",
"weight":2
}
]
I have the same customer names therefore, I want unique data. I've searched many websites & videos but I didn't get one.
Please give me appscript code to get this data!

You can do it with some Javascript acrobatics
Sample:
function makeJsonUnique() {
var json = [
{
"customerName":"cash",
"docketNo":"d87976489",
"docketDate":"2021-08-14T18:30:00.000Z",
"destination":"kanpur",
"weight":1
},
{
"customerName":"cash",
"docketNo":"d87976480",
"docketDate":"2021-08-12T18:30:00.000Z",
"destination":"kanpur",
"weight":1
},
{
"customerName":"abc",
"docketNo":"d87976482",
"docketDate":"2021-09-12T18:30:00.000Z",
"destination":"mumbai",
"weight":2
}
]
var customerNames = json.map(e=>e.customerName)
var uniqueCustomerNames = [...new Set(customerNames)]
var newJSON =[]
uniqueCustomerNames.forEach(function(name){
var tempObj ={}
tempObj.customerName = name
var jsonSubsets = json.filter(function(obj){return obj.customerName == name})
tempObj.docketNo = jsonSubsets.map(obj=>obj.docketNo).join(",")
tempObj.docketDate = jsonSubsets.map(obj=>obj.docketDate).join(",")
tempObj.destination = jsonSubsets.map(obj=>obj.destination).join(",")
tempObj.weight = jsonSubsets.map(obj=>obj.weight).join(",")
console.log(JSON.stringify(tempObj))
newJSON.push(tempObj)
})
console.log(newJSON)
}
Used methods:
map()
filter()
...newSet()
push()
join()

Related

How to filter data in columns using google app script editor

I'm facing some issues related to filter data in the columns using google app script editor.
I'm able to set a filter in columns using google app script as you can see in the above screenshot. but problem is when I'm trying to get the filtered data. it returns some number series instead of actual data as you can see below :
[20-03-09 18:19:48:395 IST] [1,2,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,26,27,28,29,30]
To set a filter :
function setFilter() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var filterSettings = {};
// The range of data on which you want to apply the filter.
// optional arguments: startRowIndex, startColumnIndex, endRowIndex, endColumnIndex
filterSettings.range = {
sheetId: ss.getActiveSheet().getSheetId()
};
// Criteria for showing/hiding rows in a filter
// https://developers.google.com/sheets/api/reference/rest/v4/FilterCriteria
filterSettings.criteria = {};
var columnIndex = 2;
filterSettings['criteria'][columnIndex] = {
'hiddenValues': ["England", "France"]
};
var request = {
"setBasicFilter": {
"filter": filterSettings
}
};
Sheets.Spreadsheets.batchUpdate({'requests': [request]}, ss.getId());
}
To get the filtered data:
function getFilteredRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var sheetId = ss.getActiveSheet().getSheetId();
let data = getIndexesOfFilteredRows(ssId,sheetId);
Logger.log(JSON.stringify(data));
}
function getIndexesOfFilteredRows(ssId, sheetId) {
var hiddenRows = [];
// limit what's returned from the API
var fields = "sheets(data(rowMetadata(hiddenByFilter)),properties/sheetId)";
var sheets = Sheets.Spreadsheets.get(ssId, {fields: fields}).sheets;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].properties.sheetId == sheetId) {
var data = sheets[i].data;
var rows = data[0].rowMetadata;
for (var j = 0; j < rows.length; j++) {
if (rows[j].hiddenByFilter) hiddenRows.push(j);
}
}
}
return hiddenRows;
}
How to set a filter in columns and get the filtered data using google app script.
Please help me with this.
In your case, the script for filtering has already worked. You want the script for retrieving the values from the filtered sheet in the Spreadsheet.
You want to achieve this using Sheets API with Google Apps Script.
If my understanding is correct, how about this modification? Please think of this as just one of several possible answers.
In your case, the function of getIndexesOfFilteredRows is modified. Using hiddenByFilter, the hidden rows and shown rows are retrieved as an object.
Modified script:
function getIndexesOfFilteredRows(ssId, sheetId) {
var object = {hiddenRows: [], hiddenRowValues: [], shownRows: [], shownRowValues: []};
// limit what's returned from the API
var fields = "sheets(data,properties/sheetId)";
var sheets = Sheets.Spreadsheets.get(ssId, {fields: fields}).sheets;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].properties.sheetId == sheetId) {
var data = sheets[i].data;
var rows = data[0].rowMetadata;
for (var j = 0; j < rows.length; j++) {
var r = [];
if (data[0].rowData[j] && Array.isArray(data[0].rowData[j].values)) {
r = data[0].rowData[j].values.map(function(e) {
var temp = "";
if (e.hasOwnProperty("userEnteredValue")) {
if (e.userEnteredValue.hasOwnProperty("numberValue")) {
temp = e.userEnteredValue.numberValue;
} else if (e.userEnteredValue.hasOwnProperty("stringValue")) {
temp = e.userEnteredValue.stringValue;
}
}
return temp;
});
}
if (r.length > 0) {
if (rows[j].hiddenByFilter) {
object.hiddenRows.push(j);
object.hiddenRowValues.push(r);
} else {
object.shownRows.push(j);
object.shownRowValues.push(r);
}
}
}
}
}
return object;
}
Result:
When above script is run for the filtered sheet, the following object which has the hidden row numbers, hidden row values, shown row numbers and shown row values is returned.
{
"hiddenRows":[0,1],
"hiddenRowValues":[["a1","b1","c1"],["a2","b2","c2"]],
"shownRows":[2,3],
"shownRowValues":[["a3","b3","c3"],["a4","b4","c4"]]
}
Reference:
DimensionProperties
If I misunderstood your question and this was not the direction you want, I apologize.
Added:
How about this sample script? In this sample script, the values filtered with filterValues can be retrieved as an object. In this case, the result is the same with your setFilter() and the modified getIndexesOfFilteredRows(). But the basic filter is not used. So please be careful this.
function myFunction() {
var filterValues = ["England", "France"]; // Please set the filter values.
var column = 3; // In this case, it's the column "C". Please set the column number.
var sheetName = "Sheet1"; // Please set the sheet name.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var values = sheet.getDataRange().getValues();
var object = values.reduce(function(o, e, i) {
if (filterValues.indexOf(e[column - 1]) > -1) {
o.hiddenRows.push(i + 1);
o.hiddenRowValues.push(e);
} else {
o.shownRows.push(i + 1);
o.shownRowValues.push(e);
}
return o;
}, {hiddenRows: [], hiddenRowValues: [], shownRows: [], shownRowValues: []});
Logger.log(object)
}
If you want to retrieve only the filtered values, this script might be suitable.
In this case, the script can run with and without V8. But when V8 is enabled, the loop speed will be fast. Ref

How do I use Sheets.Spreadsheets.getByDataFilter from app script for a filter view that is created in spreadsheet?

I am seeking help with the following case
I have a spreadsheet, and it contains few filter views - f1, f2, ...
I have an app script associated with the spreadsheet. I have enabled Resources > Advanced Google Services to access the Sheets API v4.
Currently, I access that data as
var fruits = Sheets.Spreadsheets.Values.get("1YBPXShvssFpTI-5dPSsy_N_iEVaeHezdxymsdxpTy6w", "Fruits!A:B").values;
And I get the corresponding data back.
I would now, like to only get the data that is used by the filter view, so that I do not bring the entire data which is not necessary and slows down the processing.
I saw that there is something called Sheets.Spreadsheets.getByDataFilter(resource, spreadsheetId), but I am not sure how to create the resource object.
Given my filters, and knowing the spreadsheet Id, how do I only fetch the data based on the filter names that I know?
UPDATE
My latest attempt looks like
var ss = SpreadsheetApp.getActiveSpreadsheet();
function getUnpostedItems() {
Logger.log("This function will prioritize the new items that are added into the inventory");
var sheet = ss.getSheetByName("Items");
var filterSettings = {};
filterSettings.criteria = {};
var condition = {
"condition": {
"type": "LESS_THAN",
"values": [
{ "userEnteredValue": "=NOW()-30" }
]
}
}
filterSettings['criteria'][1] = {
'condition': condition
};
var filterSettings = {
range: {
sheetId: sheet.getSheetId(),
},
}
var req = {
"setBasicFilter": {
"filter": filterSettings
}
}
// var items = Sheets.Spreadsheets.batchUpdate({'requests': [req]}, ss.getId());
var items = ss.getRange("Items!A:B").getValues()
// var items1 = Sheets.Spreadsheets.Values.get("1YBPXShvssFpTI-5dPSsy_N_iEVaeHezdxymsdxpTy6c", "Items!A:B").values
Logger.log("Found items:" + items.length);
return [];
}
But no luck so far!
As per #tanaike's help, I was able to get the following working
function getUnpostedItems() {
Logger.log("This function will prioritize the new items that are added into the inventory");
// var ss = SpreadsheetApp.getActiveSpreadsheet(); // Added
var sheet = ss.getSheetByName("Items"); // Modified
var values = sheet.getDataRange().getValues();
Logger.log("VALUES "+values.length);
//var newCriteria = SpreadsheetApp.newFilterCriteria().whenDateBefore(new Date()).build();
var newCriteria = SpreadsheetApp.newFilterCriteria().whenDateBefore(subDaysFromDate(new Date(), 30)).build();
var range = sheet.getFilter().setColumnFilterCriteria(1, newCriteria).getRange(); //The 1-indexed position of the column.
// values = range.getValues();
// I added below script.
var res = Sheets.Spreadsheets.get(ss.getId(), {
ranges: ["Items"], // <--- Please set the sheet name.
fields: "sheets/data"
});
var values = res.sheets[0].data[0].rowMetadata.reduce(function(ar, e, i) {
if (!e.hiddenByFilter && res.sheets[0].data[0].rowData[i]) {
ar.push(
res.sheets[0].data[0].rowData[i].values.map(function(col) {
return col.userEnteredValue[Object.keys(col.userEnteredValue)[0]];
})
);
}
return ar;
}, []);
Logger.log("VALUES "+values.length);
Logger.log("VALUES "+values);
//Logger.log("Found Items:" + items.length);
return [];
}

How can i make this JSON work when i deploy it as a web app

Im getting my JSON inside {} but i need it inside [] so my other app can read it.
function doGet(){
var ss = SpreadsheetApp.openById('14-vl75N4mAv9FdZNHIhX_lhtQ-XY17lOvEnLIjiSwDc');
var result={};
var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetA')
.getDataRange()
.getValues();
var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetB')
.getDataRange()
.getValues();
result.sheetA = makeObject(sheetA);
result.sheetB = makeObject(sheetB);
Logger.log(makeObject(sheetA))
Logger.log(makeObject(sheetB))
return ContentService.createTextOutput(JSON. stringify(result))
.setMimeType(ContentService.MimeType.JSON);
}
function makeObject(multiArr) {
var obj = [];
for(var i=1;i<multiArr.length;i++)
{
obj.push( {
"Question": multiArr[i][1],
"Answers" : [multiArr[i][3],multiArr[i][4],multiArr[i][5],multiArr[i][6]],
"right answer" : multiArr[i][7],
}
)
}
var myJSON=[{ "module": multiArr[1][0],
"Questions" : obj
}]
return JSON.stringify(myJSON);
}
CURRENT OUTPUT:
"{
sheetA: "[{"module":"ModuleA","Questions":[{"Question":"2+2=?","Answers":[7,11,12,4],"right answer":4},{"Question":"Q2","Answers":[1,2,1,3],"right answer":3},{"Question":"Q3","Answers":[10,230,23,44],"right answer":44}]}]",
sheetB: "[{"module":"ModuleB","Questions":[{"Question":"2+2=?","Answers":[7,11,12,4],"right answer":4},{"Question":"Q2","Answers":[1,2,1,3],"right answer":3},{"Question":"Q3","Answers":[10,230,23,44],"right answer":44}]}]"
}"
EXPECTED OUTPUT:same thing but all inside [...]

How do i get a JSON file out of my SpreadSheet

I want to get a JSON out my spreadsheet that looks like this() and to extract a JSON file like this:
[{ "module": "ModuleA",
"Questions" : [{
"Question": "xxxx",
"Answers" : ["1","2","3"],
"right answer" : "2",
}
]
This is what i have by now but its not in the coreect hierarchy
function doGet(){
var ss = SpreadsheetApp.openById('14-vl75N4mAv9FdZNHIhX_lhtQ-XY17lOvEnLIjiSwDc');
var result={};
var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetA')
.getDataRange()
.getValues();
var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetB')
.getDataRange()
.getValues();
result.sheetA = makeObject(sheetA);
result.sheetB = makeObject(sheetB);
Logger.log(result.sheetA)
//return ContentService.createTextOutput(JSON. stringify(result))
//.setMimeType(ContentService.MimeType.JSON);
}
function makeObject(multiArr) {
var obj = {};
var headers = multiArr.shift()
for(var i = 0; i< headers.length; i++){
obj[headers[i]]= multiArr.map(function(app){
return app[i];
});
}
return obj;
}
What about this solution?
function doGet(){
var ss = SpreadsheetApp.openById('14-vl75N4mAv9FdZNHIhX_lhtQ-XY17lOvEnLIjiSwDc');
var result={};
var sheetA = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetA')
.getDataRange()
.getValues();
var sheetB = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheetB')
.getDataRange()
.getValues();
result.sheetA = makeObject(sheetA);
result.sheetB = makeObject(sheetB);
Logger.log(makeObject(sheetA))
}
function makeObject(multiArr) {
var obj = [];
for(var i=1;i<multiArr.length;i++)
{
obj.push( {
"Question": multiArr[i][1],
"Answers" : [multiArr[i][2],multiArr[i][3],multiArr[i][4]],
"right answer" : multiArr[i][5],
}
)
}
var myJSON=[{ "module": multiArr[1][0],
"Questions" : obj
}]
return JSON.stringify(myJSON);
}
You can push into an array your data formatted according to the hierarchy of
your choice, populate it within a loop with the contents of each row
in your sheet and then JSON.stringify it.
This works as above provided you have only one module per sheet. Otherwise, you need to implement an additional function which would detect in which row ModuleA ends and ModuleB starts.

Trying to fetch JSON data and put it to googlesheet

I have problem with value setting in googlesheet. Googlesheet setValue support only array but i need to put object in rows.
I tried use appendRow but it won't work in custom functions. I also tried setValue with converting my objects to array but then i missed some data.
This is my fetching function. It works and gets all data i need but it's really hard for me to place it into googlesheet.
function importTrelloJSON(url){
var response = UrlFetchApp.fetch(url);
var content = response.getContentText();
var data = JSON.parse(content);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var trelloJSON = data.map(function(el, index) {
var customFieldItems = el.customFieldItems.map(function(el){
return [el.idCustomField, el.value.number];
});
return { name: el.name, customFieldItems: customFieldItems };
});
retrun trelloJSON;
}
and this is my JSON structure, sometimes there is nested data
[
{
"id": "5ce26ef1d5bdac4ec20e8982",
"name": "WWW",
"customFieldItems": []
},
{
"id": "5ced04d96ec7ed6120b5e91d",
"name": "Marketing",
"customFieldItems": []
},
{
"id": "5cfed3d8e88f931008aa58ad",
"name": "Reset softu Android",
"customFieldItems": [
{
"id": "5cfed4145d019516555a9086",
"value": {
"number": "100"
},
"idCustomField": "5ced79c27bbd7102945ba1ff",
"idModel": "5cfed3d8e88f931008aa58ad",
"modelType": "card"
}
]
},
I tried using ready importJSON function https://github.com/bradjasper/ImportJSON but it's not working with my queries.
Thanks for help.
//edit
Now i can display data but when i push to array i have problem with range. The number of data columns does not match the number of columns in the range.
I tried Math.max.apply(Math, trelloJSON.map(function (el) { return el.length })). But it's not working anymore.
Here is my new code:
function importTrelloJSON(url){
var response = UrlFetchApp.fetch(url);
var content = response.getContentText();
var data = JSON.parse(content);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var mainArray = new Array();
var trelloJSON = data.map(function(el, index) {
mainArray = [];
mainArray.push(el.name);
el.customFieldItems.map(function(el){
mainArray.push(el.idCustomField);
mainArray.push(el.value.number);
});
Logger.log(mainArray);
return mainArray;
});
sheet.getRange(1,1, trelloJSON.length, Math.max.apply(Math, trelloJSON.map(function (el) { return el.length }))).setValues(trelloJSON);
}