How should I structure my data so it works with firebase? - firebase

I want to update some data in the forms of
wordBank = {
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
}
the goal is to able to extract and display all the values of all the keys in each JSON object. How do I create this format on firebase? do I use .update? or something else?
currently I could only get firebase .update() to work with an array but it gives me data like this
wordBank = [
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
];
where each word-object is an index in the array.
Here's how I construct my wordObjects:
function getWords() {
if (document.getElementsByClassName("vortarobobelo").length != 0){
var words;
words = document.getElementsByClassName("vortarobobelo")[0].children[0].children;
for (var i =0; i < words.length; i++) {
var localBank = {} //creating the local variable to store the word
var newWord = words[i].children[0].innerText; // getting the word from the DOM
var newTranslation = words[i].children[1].innerText; // getting the translation from the DOM
localBank.word = newWord;
localBank.translation = newTranslation;
localBank.count = 0 //assuming this is the first time the user has clicked on the word
console.log(localBank);
wordBank[localBank.word] = localBank;
fireBank.update(localBank);
}
}
}

If you want to store the items within an object, you need to pick keys to store them against.
You can't store unkeyed values inside an object in Javascript. This would result in a syntax error:
wordBank = {
{word:"aprobi", translation:"to approve", count:2},
{word:"bati", translation:"to hit, to beat, to strike", count:1},
{word:"da", translation:"of", count:1}
}
The other option is to store them in an array, in which case the keys will be automatically assigned as array indices. Just like your second example.
Maybe you want to store the word objects, using the word itself as a key?
wordBank = {
aprobi: {word:"aprobi", translation:"to approve", count:2},
bati: {word:"bati", translation:"to hit, to beat, to strike", count:1},
da: {word:"da", translation:"of", count:1}
}
This would be easy to do with Firebase. Let's say you have all of your word objects as a list.
var ref = new Firebase("your-firebase-url");
wordObjects.forEach(function(wordObject) {
ref.child(wordObject.word).set(wordObject);
});
Or you could create the object with Javascript, then add it to Firebase using .update.
var wordMap = {};
wordObjects.forEach(function(wordObject) {
wordMap[wordObject.word] = wordObject;
});
ref.update(wordMap);

Related

How to create multi items/records or save item/record array at one time in client script file

I want to create multiple records at the same time using client script. This is what I'm doing:
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
for(var i = 0 ; i < 3; i ++) {
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
But the result I'm getting is this one:
The three records are created but the only the first one has data. The other two records have empty values on their fields. How can I achieve this?
Thanks.
Update(2019-3-27):
I was able to make it work by putting everything inside the for loop block. However, I have another question.
Is there any method like the below sample code?
var recordData = [Data1, Data2, Data3]
var ceateDatasource;
var newItem = new Array(recordData.length) ;
for(var i = 0 ; i < recordData.length; i ++) {
ceateDatasource = app.datasources.Reservation.modes.create;
newItem[i] = ceateDatasource.item;
newItem[i].User = recordData[i].user;
newItem[i].Description = recordData[i].Description;
newItem[i].Location_Lab_fk = recordData[i].Location_Lab_fk;
newItem[i].Area_fk = recordData[i].Area_fk;
newItem[i].Equipment_fk = recordData[i].Equipment_fk;
newItem[i].Start_Date = recordData[i].Start_Date;
newItem[i].Start_Hours = recordData[i].Start_Hours;
newItem[i].Start_Minutes = recordData[i].Start_Minutes;
newItem[i].End_Date = recordData[i].End_Date;
newItem[i].End_Hours = recordData[i].End_Hours;
newItem[i].End_Minutes = recordData[i].End_Minutes;
}
// Create the new item
ceateDatasource.createItem();
First, it prepares an array 'newItem' and only calls 'ceateDatasource.createItem()' one time to save all new records(or items).
I try to use this method, but it only saves the last record 'newItem[3]'.
I need to write a callback function in 'ceateDatasource.createItem()' but Google App Maker always show a warning "Don't make functions within a loop". So, are there any methods to call 'createItem()' one time to save several records? Or are there some functions like 'array.push' which can be used?
Thanks.
As per AppMaker's official documentation:
A create datasource is a datasource used to create items in a particular data source. Its item property is always populated by a draft item which can be bound to or set programmatically.
What you are trying to do is create three items off the same draft item. That why you see the result you get. If you want to create multiple items, you need to create a draft item for each one, hence all you need to do is put all your code inside the for loop.
for(var i = 0 ; i < 3; i ++) {
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
If you want to save several records at the same time using client script, then what you are looking for is the Manual Save Mode. So all you have to do is go to your model's datasource and click on the checkbox "Manual Save Mode".
Then use the same code as above. The only difference is that in order to persist the changes to the server, you need to explicitly save changes. So all you have to do is add the following after the for loop block:
app.datasources.Reservation.saveChanges(function(){
//TODO: Callback handler
});

Limit with getting info about audience from Analytics API

I'm trying to get audienc name aduience id etc we' ve created on our google analytics account. We have around 2,4k audiences list but I can just get 999 of them. I can't find any soultions. Code is below
function main() {
var spreadsheet = SpreadsheetApp.openByUrl('https://docs.google.com/spreadshe');
var sheet = spreadsheet.getSheetByName('Sh');
function listRemarketingAudiences(accountId, propertyId) {
var request = Analytics.Management.RemarketingAudience.list(
accountId,
propertyId
);
var leno = Object.keys(request).length
console.log(leno);
sheet.getRange(1,1).setValue("audianceName");
sheet.getRange(1,2).setValue("audianceId");
sheet.getRange(1,3).setValue("audianceDefinition");
sheet.getRange(1,4).setValue("audianceDescription");
for ( var i = 2; i <3000; i++) {
var audianceName = request.items[i+154].name ;
Logger.log(audianceName);
console.log(i);
sheet.getRange(i,1).setValue("elo")
var audianceId = request.items[i].id ;
sheet.getRange(i,2).setValue(audianceId);
// var audianceId = request.items[i].
var audienceDefinition = request.items[i].audienceDefinition ;
sheet.getRange(i,3).setValue(audienceDefinition);
var audienceDescription = request.items[i].description ;
sheet.getRange(i,4).setValue(audienceDescription);
};
}
listRemarketingAudiences('xxxxx', 'UA-xxxxx-1');
}
Currently you are supplying only the required parameters: accountId and webPropertyId. These are necessary to identify the Analytics property, where you are looking for the data.
Based on the documentation, optional parameters can be passed, which are actually in connection with the pagination, which you are trying to achieve.
As the developer guide is not mentioning the absolute limit of the result, you could experiment with higher limits, with a code something like this:
request = gapi.client.analytics.management.remarketingAudience.list(
{
'accountId': accountId,
'webPropertyId': propertyId,
'max-results': 5000
}
If you can't get all the data at once, you need to implement paging yourself, where an other paramerer, start-index will be necessary. You need to call the function several times, preferably from a loop, where start index is continuously increased.
request = gapi.client.analytics.management.remarketingAudience.list(
{
'accountId': accountId,
'webPropertyId': propertyId,
'start-index': 999,
'max-results': 1000
}
I wrote sth like this:
var optional = {'startIndex': 12,
'maxresults': 212};
function listRemarketingAudiences (accountId, propertyId, optional){
var request = Analytics.Management.RemarketingAudience.list(
accountId,
propertyId,
optional.maxresults
);
and an error occure:
We're sorry, a server error occurred. Please wait a bit and try again. (line 9, file "Code")

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.

Crossfilter: how to build custom reduce functions when I want to access a specific array-value?

I have constructed my crossfilter-setup a bit different than in most examples I can find, namely:
I have data-array d with multiple data-sources included, among which is data1.
var cf = crossfilter(d3.range(0, d.data1.length));
Then I construct my dims like:
var dim = cf.dimension(function(i) { return d.data1[i].id; });
And I construct my groups like:
var group = dim.group().reduceSum(function(i) { return d.data1[i].total;});
This all works fine, but when I want to create custom reduce functions, the extra parameter i is giving me trouble.
var reduceAddPerc = function(p,v) {
p.sumOfSub += d.data1[i].var1;
p.sumOfTotal += d.data1[i].total;
p.finalVal = p.sumOfSub / p.sumOfTotal;
return p;
};
var reduceRemovePerc = function(p,v) {
p.sumOfSub -= d.data1[i].var1;
p.sumOfTotal -= d.data1[i].total;
p.finalVal = p.sumOfSub / p.sumOfTotal;
return p;
};
var reduceInitialPerc = function() {
return {sumOfSub:0, sumOfTotal:0, finalVal:0 };
};
And then defining the group with:
var group = dim.group().reduce(reduceAddPerc,reduceRemovePerc,reduceInitialPerc);
This doesn't work obviously, since the parameter i is now not known within the function. But I've tried adding the parameter (p,v,i), or nesting the functions by creating an additional function with parameter i around the (p,v) function, and also creating an additionao function(i) within the (p,v) function, but I cannot get this to work.
Does anyone have any help to offer?
In the custom reduce functions, the v parameter is the record currently being "reduced". In this case, it should be your counter, so just use it where you would normally use i. Is that not working?

Resources