Read Data from Firebase to Sheets - firebase

I'm having trouble splitting the data once I have retrieved it using .getData().
The firebase data is in the form:
mainTag: subTag1:"["Test1",70,0,18]", subTag2:"["Test2",65,2,18]", etc...
This is as far as I've managed to get as I'm not sure of the format of the data. I can't directly set it to the value of a single cell or a range of cells because the parameters don't match the method signature for the sheet. I've tried splitting the data as if it were an object and as if it were a string but keep getting nulls logged in the logger so I'm not sure what to do with it.
function getData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("TestSheet");
var range = sheet.getRange("A1:D2");
var firebaseUrl = "https://.....firebaseio.com/";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl);
var data = base.getData("mainTag");
//range.setValues(data);
Logger.log(data);
Logs: {subTag2=["Test2",65,2,18], subTag1=["Test1",70,0,18]}
}
My objective is to set the value of 4 cells in a row to the data inside each subtag. (A1="Test1", B1=70, C1=0, D1=18) Then subtag2 is in row 2 and so on. I haven't got to splitting the data yet as I'm not sure how to format the data from firebase for it to be able to be used in .setValues()

You need to loop through the subtags and access the values belonging to each key
This can be best achieved with Object.keys().
Sample:
var data = base.getData("mainTag");
var array = [];
for(var i in data) {
var newdata = Object.keys(data[i]).map(function (key) {
return data[i][key];
});
array.push(newdata);
}
var range = sheet.getRange(1,1, array.length, array[0].length);
range.setValues(array);

Related

Exception: Bad value (line 9, file "Code")

I want to read my data from my firebase and write it in google sheet. When i run this Apps Script I got the error
Exception: Bad value (line 9, file "Code")
var ss= SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var range=sheet.getRange(1,1,4,2);
var data= getFirebaseData("Entries");
Logger.log(data)
range.setValues(JSON.parse(data))
}
function getFirebaseData(data){
var firebaseUrl = "**";
var secret = "**";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl,secret);
var result = base.getData(data);
return result;
}
the data in Firebase is like this:
Entries
date:"09/09/2020"
docAmount:88
docNo:55
partyName: "ffg"
Solutions that I might accept,(solve this issue)or (show a better way to do the process)
You want to write an object's (data) key/value pairs to two columns in a sheet. setValues accepts a 2D array, not an object, so you should first transform data to a 2D array:
const array = Object.keys(data).map(key => [key, data[key]]);
sheet.getRange(1, 1, array.length, array[0].length).setValues(array);
Note:
Making the range dimensions dependent on the array dimensions (array.length, array[0].length) will give you more flexibility (what if the object has 5 properties instead of 4?).
This will only work for simple objects, not if they have nested properties.
Reference:
setValues(values)
Object.keys()
getData(path, optQueryParameters)

Firebase RealtimeDB to Google Sheets through AppScript

I am trying to write Firebase RealtimeDB data into a Google Sheets spreadsheet through Google Appscript.
This is what my RealtimeDB looks like:
My goal is
I have tried the following code snippet:
function writeSheets() {
var firebaseUrl = "https://<mydatabase>.firebaseio.com/Attendees";
var base = FirebaseApp.getDatabaseByUrl(firebaseUrl);
var data = base.getData();
var ss = SpreadsheetApp.openById("<mySheet>");
var sheet = ss.getSheetByName("Sheet1");
var num = 2;
range = ss.getRange("A"+num+":B"+num+"");
for(var i in data) {
var values = [[ data[i].ID, data[i].Name ] ];
range.setValues(values);
num += 1;
range = sheet.getRange("A"+num+":B"+num+"");
}
console.log(JSON.stringify(data));
}
It seems to print empty cells into Google Sheet. Not exactly sure why.
Any input would be greatly appreciated. Thanks.
EDIT:
Console Log :
[20-04-08 20:46:26:102 HKT] TypeError: Cannot read property 'ID' of null
at writeSheets(Code:13:27)
There is a extra null in the data. Filter it out and map the array of objects to a 2D array and setValues the 2D array:
const data = [null,{"ID":1001,"Name":"Bob"},{"ID":1069,"Name":"Steve"},{"ID":1420,"Name":"Bill"}];
const out = data.filter(Boolean).map(Object.values);
console.log(out);
/*SetValues the entire array*/
//sheet.getRange(1,1,out.length, out[0].length).setValues(out);

How to separate multiple columns from a range in an array?

I have a range of data in a Google Sheet and I want to store that data into an array using the app script. At the moment I can bring in the data easily enough and put it into an array with this code:
var sheetData = sheet.getSheetByName('Fruit').getRange('A1:C2').getValues()
However, this puts each row into an array. For example, [[Apple,Red,Round],[Banana,Yellow,Long]].
How can I arrange the array by columns so it would look: [[Apple,Banana],[Red,Yellow],[Round,Long]].
Thanks.
It looks like you have to transpose the array. You can create a function
function transpose(data) {
return (data[0] || []).map (function (col , colIndex) {
return data.map (function (row) {
return row[colIndex];
});
});
}
and then pass the values obtained by .getValues() to that function..
var sheetData = transpose(sheet.getSheetByName('Fruit').getRange('A1:C2').getValues())
and check the log. See if that works for you?
Use the Google Sheets API, which allows you to specify the primary dimension of the response. To do so, first you must enable the API and the advanced service
To acquire values most efficiently, use the spreadsheets.values endpoints, either get or batchGet as appropriate. You are able to supply optional arguments to both calls, and one of which controls the orientation of the response:
const wb = SpreadsheetApp.getActive();
const valService = Sheets.Spreadsheets.Values;
const asColumn2D = { majorDimension: SpreadsheetApp.Dimension.COLUMNS };
const asRow2D = { majorDimension: SpreadsheetApp.Dimension.ROWS }; // this is the default
var sheet = wb.getSheetByName("some name");
var rgPrefix = "'" + sheet.getName() + "'!";
// spreadsheetId, range string, {optional arguments}
var single = valService.get(wb.getId(), rgPrefix + "A1:C30");
var singleAsCols = valService.get(wb.getId(), rgPrefix + "A1:C30", asColumn2D);
// spreadsheetId, {other arguments}
var batchAsCols = valService.batchGet(wb.getId(), {
ranges: [
rgPrefix + "A1:C30",
rgPrefix + "J8",
...
],
majorDimension: SpreadsheetApp.Dimension.COLUMNS
});
console.log({rowResp: single, colResp: singleAsCols, batchResponse: batchAsCols});
The reply will either be a ValueRange (using get) or an object wrapping several ValueRanges (if using batchGet). You can access the data (if any was present) at the ValueRange's values property. Note that trailing blanks are omitted.
You can find more information in the Sheets API documentation, and other relevant Stack Overflow questions such as this one.

Performance server scripting

I have table with multiple customerKey values assigned to a numeric value; I wrote a script where foreach row of data I scan whole table to find all values assigned to the current customerKey and return a highest one;
I have a problem with performance - script processes around 10 records per second - any ideas how to improve this or maybe propose an alternative solution plesae?
function getLastest() {
var date = app.models.magicMain.newQuery();
var date_all = date.run();
date_all.forEach(function(e) { // for every row of date_all
var temp = date_all.filter(function(x) {
return x.SubscriberKey === e.SubscriberKey; // find matching records for the current x.SubscriberKey
});
var dates = [];
temp.forEach(function(z) { // get all matching "dates"
dates.push(z.Date);
});
var finalValue = dates.reduce(function(a, b) { // get highest dates value (integer)
return Math.max(a, b);
});
var record = app.models.TempOperatoins.newRecord(); // save results to DB
record.email = e.SubscriberKey.toString() + " " + finalValue.toString();
app.saveRecords([record]);
});
}
The only suggestion I have would be to add:
var recordstosave = [];
At the top of your function.
Then replace app.saveRecords([record]) with recordstosave.push(record).
Finally outside of your foreach function do app.saveRecords(recordstosave).
I saw major processing time improvements doing this rather than saving each record individually inside a loop.

Google Sheets: delete rows containing specified data

I'm new to Java scripting and Google Apps Scripts so i am sorry if this has already been answered. I was not able to find what i was looking for over the last few months of working on this project.
I am working on a variant of the scripts here:
Delete row in Google Sheets if certain "word" is found in cell
AND
Google Sheet Script - Find Value in Col and Delete Row
I want to create a button, or menu, that will allow someone to enter specific data, and have each row in the spreadsheet containing that data deleted.
I have a test sheet here that illustrates the data i'm working with, formulas i'm using, and has the beginning of the script attached to it:
https://docs.google.com/spreadsheets/d/1e2ILQYf8MJD3mrmUeFQyET6lOLYEb-4coDTd52QBWtU/edit?usp=sharing
The first 4 sheets are pulling data from the "Form Responses 1" sheet via a formula in cell A:3 in each sheet so the data would only need to be deleted from the "Form Responses 1" sheet to clear it from the rest of the sheets.
I tried working this in but i do not think i am on the right track.
https://developers.google.com/apps-script/guides/dialogs
I also posted this on Google Docs Help Forum 60 days ago, but have not received any responses.
Any help would be greatly appreciated.
There's a few steps. For usability of UI this takes a little longer code. In concise form:
The user activates a dialog and enters a string.
Rows w/ the string are deleted (with error handling and confirmation)
(Hopefully this gets you started and you can tailor it to your needs)
Function that initiates the menu:
function onOpen(){
SpreadsheetApp.getUi()
.createMenu('My Menu')
.addItem('Delete Data', 'deleteFunction')
.addToUi();
}
The main workhorse:
function deleteFunction(){
//declarations
var sheetName = "Form Responses 1";
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName(sheetName);
var dataRange = sheet.getDataRange();
var numRows = dataRange.getNumRows();
var values = dataRange.getValues();
var delete_string = getUIstring();//open initial UI, save value
if (delete_string.length < 3) return shortStringError()//UI to protect your document from an accidental entry of a very short string.
//removing the rows (start with i=2, so don't delete header row.)
var rowsDeleted = 0;
for (var i = 2; i <= numRows; i++){
var rowValues = values[i-1].toString();//your sheet has various data types, script can be improved here to allow deleting dates, ect.
if (rowValues.indexOf(delete_string) > -1){
sheet.deleteRow(i - rowsDeleted);//keeps loop and sheet in sync
rowsDeleted++;
}
}
postUIconfirm(rowsDeleted);//Open confirmation UI
}
Isolated UI functions to help make above function more concise:
function getUIstring(){
var ui = SpreadsheetApp.getUi();
var response = ui.prompt("Enter the target data element for deletion")
return response.getResponseText()
}
function postUIconfirm(rowsDeleted){
var ui = SpreadsheetApp.getUi();
ui.alert("Operation complete. There were "+rowsDeleted+" rows deleted.")
}
function shortStringError(){
var ui = SpreadsheetApp.getUi();
ui.alert("The string is too short. Enter a longer string to prevent unexpected deletion")
}
I'll just show a way to delete the cell value if it matches your search criteria. It's up to you to connect it to buttons ,etc.
You'll loop through a Sheet Range. When you find the word match, delete it using clearContent()
function deleteSpecificData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("Sheet1!A1:C4");
var values = range.getValues();
var numArray = [1,2,3,4,5,6,7,8,9];
var deleteItem = "Garen";
Logger.log(range);
for(var i=0; i< values.length; i++){
for(var j=0; j<values[i].length; j++){
if(values[i][j] == deleteItem){
var row = numArray[i];
var col = numArray[j];
var range = sheet.getRange(row,col).clearContent();
}
}
}
}
Before:
After:

Resources