Javascript adding array to specific index - javascript

When i have the following global variable on my application start :
events = [];
Then if i go fetch something with ajax with the following simplified code snippet :
events[0] = [];
setTimeout(function fetchEventsThisWeek(){
$.ajax({
url: '/event/getEventsBetweenDates',
type: 'POST',
data : { from_date : currentweek.from_date.toString("yyyy-MM-d") , to_date : currentweek.to_date.toString("yyyy-MM-d"), limit : limit, offset : offset },
success: function(data) {
jQuery.each(data, function(index){
events[0].push(data[index]['attributes']);
});
offset = offset + limit;
entry_count = entry_count + data.length;
if(data.length < limit) { // We reached the end of the table so we don't need to call the function again
renderEvents(current, offset - limit, entry_count);
//Make sure the current next week button gets enabled because we are done with the results
} else {
renderEvents(current, offset - limit, offset);
setTimeout(fetchEventsThisWeek, 150); // There are more results, continue
}
}
})
}, 150);
This recursive function just fetches all events between two dates and keeps calling itself until there is no record in the db left.
My problem is:
With the variable:
events[0] = [];
I want to specify the index of the array as my week entry. So if i look for a specific week, i can get all the entries that already have been fetched from my array by the array index.
My problem is, when i want to fetch more weeks, so for example:
events[1] = [];// Index 1 would represent the next week
The array just expands in size and all gets appended to the end, so i have one big array and not a multidimensional one. Why is this? And how can i achieve this behaviour?
Edit:
Let me expand on my question.
I need several arrays of json objects in the events variable.
So..
events[0] = [ /*contains array of json objects */];
events[1] = [ /*contains array of json objects */];
events[2] = [ /*contains array of json objects */];
Each array index represent 1 week. So index 0 is the current week, index 1 is week 1, index 2 is week 2 and so forth. I even want to do the following but i don't know if this is even possible:
events[-1] = [ /*contains array of json objects */];
Where the index -1 would be 1 week in the past. Could anybody let me know if this is possible?

You're looking for Array.unshift:
events.unshift([]);
Documentation

Related

Google script loop check for duplicate before writing data

I have a script which reads data from a site, stores the data in an array variable and then writes the data to a google sheet.
Per item id (JSON format), the data which is read is of the form:
[timestamp number text1 text2]
and these details are duplicated across different ids in a for loop.
What i'm left with on the sheet is per row (one item in each cell):
timestamp(id1) number1(id1) text1(id1) text2(id1) timestamp(id2) number1(id2) text1(id2) text2(id2) timestamp(id3) number1(id3)...etc
each row will contain only a single value for timestamp, however the timestamp variable is written multiple times. Is it possible to adapt my script to check column A of the bottom row on my sheet and only write the new row if the timestamp in the current bottom row is different to the timestamp in the new row about to be written.
for loop iterates through json file and stores data in "values" variable.
{
{.....
let values = [];
values.push(timestamp, number1, text1, text2); //final line of for loop
}
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("test");
var range = ss.getRange(3, 1, 1, values.length);
if (range.isBlank()) {
range.setValues([values]);
} else {
ss.appendRow(values);
}
}
2 Requests:
a) I would like the timestamp variable to only be written once, in column A.
b) I would like the script to check the last written row to ensure that the timestamp value printed in column A is different to the value about to be written in the new row. If it is the same, do not write to the row.
Thanks
So for Request A: You need to change the array you are passing to the setValues()method. If you already know which columns these are, then you can modify the array by replacing the existing value with an empty string.
const outputRow = [ … ]; // This is where your current output is set
const emptyTheseColumns = [3, 6, 9]; // columns C, F, I
const cleanedOutputRow = outputRow.map( (item, index) => {
const column = index + 1; // columns start at 1, index at 0
// return empty string for stated columns
if( emptyTheseColumns.indexOf( column ) != -1){
return ""
}
// otherwise return the current value
return item
});
// then use the new array in setValues( cleanedOutputRow )

Sort Nested Json Object based on value in for loop?

Hoping someone can help me out here or at least point me in the right direction. I have spent hours trying to get this sorted and I am lost.
The code below is just mock, my actual json is returned via AJAX using jquery. My problem is not sorting, but sorting on a nested json object.
I am trying to sort the json output based on cost. (lowest cost to highest), my attempts have failed and I cannot get this sorted. I keep getting "sort" is undefined.
Any help would be appreciated or if you can just point out what I am doing wrong here.
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
/*
This doesnt work and returns undefined.
json["shipping_method"]["quote"].sort(function(a, b) {
return a['cost'] > b['cost'];
});
// I found this example, but also didn't work.
custSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
const a = prop2 ? e1[prop1][prop2] : e1[prop1],
b = prop2 ? e2[prop1][prop2] : e2[prop1],
sortOrder = direction === "asc" ? 1 : -1
return (a < b) ? -sortOrder : (a > b) ? //sortOrder : 0;
};
json.sort(custSort("quote", "cost", "desc"));*/
json = JSON.parse(json);
for (var i in json["shipping_method"]) {
// EDIT:: I want the sorting to occur here if possible.
for (j in json["shipping_method"][i]["quote"]) {
//EDIT:: I want to keep this for loop, but with the results sorted by cost
console.log(json["shipping_method"][i]["quote"][j]["cost"]);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Convert Object to Sorted Array
The object can be flattened out so that parent keys are included in the deep object as it's been iterated over. An early example to that can be found in this answers edit history. It has been removed since information like the quote-id was not deemed important.
Below is an example of using Object.values, which traverses an object and only returns an array of that objects values (discarding the keys). The values can then be sorted as intended, by cost.
const json = JSON.parse(getData());
for (let method in json["shipping_method"]) {
// cache
let quotes = json['shipping_method'][method]['quote']
// convert object to array and sort
let sortedQuotes = Object.values(quotes).sort((a, b)=>a.cost-b.cost);
console.log(sortedQuotes)
}
/* Dummy Data */
function getData() {
return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}
.as-console-wrapper {
max-height: 100vh !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Quotes by Cost per Shipping Method
This assumes that the quote ID is needed (perhaps to be placed on a row); otherwise this can be simplified using Object.values in place of Object.entries (amongst other changes).
Disregard what the output function is doing. It is a quick example, that doesn't ensure proper cell order and has a host of other limitations and vulnerabilities. It is only used to demonstrate that the original quote data is still available after sorting.
const data = JSON.parse(getData());
for (let method in data.shipping_method) {
output({row: method}, {class:'capitalize'})
// cache
let quotes = data.shipping_method[method].quote
let sortContent = Object.entries(quotes);
let sortedQuotes = sortContent.sort((a,b)=>a[1].cost-b[1].cost).map(i=>i[0]);
for (let quoteId of sortedQuotes){
let quoteInfo = quotes[quoteId];
output({cell: quoteInfo})
}
}
/* Dummy Data */
function getData() {
return '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
}
/* Really simple output for demo purpose */
function output(data, options={}){
if ('row' in data){
let $col = $('<td></td>', options).html(data.row)
let $row = $('<tr></tr>').append($col);
$('tbody').append( $row )
}
else if ('cell' in data){
let $row = $('<tr></tr>')
for( let key in data.cell ){
let $col = $('<td></td>', options).html(data.cell[key])
$row.append($col)
}
$('tbody').append( $row )
}
}
.capitalize {
text-transform: uppercase;
}
td {
min-width: 5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead></thead>
<tbody></tbody>
</table>
Your objects can have any amount of properties and you can choose to sort by whatever object property you want, number or string, if you put the objects in an array.
var item = JSON.parse(json).shipping_method.ups.quote;
Use Object.values() to get array of values of the JSON object and then use slice() method to copy the array of JSON objects and not just make a reference.
var byCost = Object.values(item).slice(0);
Finally you can use sort function for that array of objects.
byCost.sort(function(a,b) {return a.cost - b.cost});
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
var item = JSON.parse(json).shipping_method.ups.quote;
var byCost = Object.values(item).slice(0);
byCost.sort(function(a,b) {return a.cost - b.cost});
console.log(byCost)
It doesn't seem like you are accessing the right path here... Looking at the JSON you posted you should be attempting to sort shipping_method.ups.quote its also worth noting that shipping_method.ups.quote is an object and must be converted to an Array to invoke .sort as this method lives on the Array prototype.
This can be done several ways but Object.values() is one such way.
you may try the following,
json = JSON.parse(json);
let item = json.shipping_method.ups.quote,
temp = [];
for (let key in item) {
temp.push(item[key]);
}
temp.sort((x, y) => x.cost - y.cost);
json.shipping_method.ups.quote = temp;
converting your object into array and then sort;
As i can see , your problem is to sort the object with cost as their keys should stays same ,
try out this ,
var json = '{"shipping_method":{"ups":{"title":"United Parcel Service","quote":{"12":{"code":"ups.12","title":"UPS 3 Day Select","cost":117.3,"tax_class_id":"0","text":"$117.30"},"13":{"code":"ups.13","title":"UPS Next Day Air Saver","cost":242.52,"tax_class_id":"0","text":"$242.52"},"14":{"code":"ups.14","title":"UPS Next Day Air Early A.M.","cost":279.95,"tax_class_id":"0","text":"$279.95"},"03":{"code":"ups.03","title":"UPS Ground","cost":54.62,"tax_class_id":"0","text":"$54.62"},"02":{"code":"ups.02","title":"UPS 2nd Day Air","cost":177.31,"tax_class_id":"0","text":"$177.31"},"01":{"code":"ups.01","title":"UPS Next Day Air","cost":248.08,"tax_class_id":"0","text":"$248.08"}},"sort_order":"","error":""}}}';
var json = JSON.parse(json);
let data = []
for(var i in json.shipping_method.ups.quote){
data.push(json.shipping_method.ups.quote[i])
data.sort((a,b) => a.cost - b.cost);
}
This create those key agains as they are before
let final = {} ;
data.forEach(el => final[el.code.split('.')[1]] = el);
Finally update the qoute with the latest sorted quotes :
json.shipping_method.ups.quote = final;

Appending a 2D array to another 2D array, gets inserted as a single row instead

I'm having problems to append a 2D array at the end of another 2D array.
The first array called array_from_sheet I construct from reading a range of cells in Google sheet, from a range of 5 columns and 100 rows. This first array looks like this in debug window:
[["2017-12-02T16:49:48.9Z", 1040036, 399.07, 0.01, "sell"], ["2017-12-02T16:49:48.9Z", 1040037, 399.08, 1.12907707, "sell"], [....
The second array called trades comes from a JSON string that i parsed and looks like this in debug window (it has 100 rows and 5 columns):
[["2017-12-02T18:06:55.909Z", 1040574, "399.00000000", "1.12619681", "sell"], ["2017-12-02T18:06:55.829Z", 1040573, "399.00000000", "1.31054161", "sell"], [...
this is before my splice command: trades.splice(1, 0, array_from_sheet);
After my splice command, the trades array looks like this in debug window:
[["2017-12-02T18:06:55.909Z", 1040574, "399.00000000", "1.12619681", "sell"], [["2017-12-02T16:49:48.9Z", 1040036, 399.07, 0.01, "sell"], [...
You can see the second row now starts with a double bracket, problem i guess.
The debug window says it has now 101 rows while it should have 200. The second row of the new array now has 100 elements into it, looks like array_from_sheet got inserted here instead on the same row.
(I tried the .push command but got same problem)
(array_from_sheet.length returns 100, so it appears to be 100 rows)
Here's my code:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var first = ss.getSheetByName("trades");
first.activate();
//var sheet = SpreadsheetApp.openById('DEV_GDAX Order book and trades')
//var APIPullSheet = sheet.getSheetByName("APIPull");
//first.getRange('A2:D19999').clearContent();
// call the trades from GDAX into var parcedData- should add error handling here if server does not respond or return error code
var url = "https://api.gdax.com/products/ETH-EUR/trades"
var responseAPI = UrlFetchApp.fetch(url)
var parcedData = JSON.parse(responseAPI.getContentText());
// creates new empty array trades, adds headers on first row,
var trades = new Array ();
//trades.push(['time', 'trade_id', 'price', 'size','side']) hll: i removed this line as i don't need headers, i have them on row1 in sheet
// create temp array for a row, read from parsedData, push to temp, repeat, then push to temp (more or less)
var keys = ['time', 'trade_id', 'price', 'size','side'];
for (var i in parcedData) {
var temp = [];
for (var j in keys) {
temp.push(parcedData[i][keys[j]]);
}
trades.push(temp);
//Logger.log(trades)
}
//here i should remove duplicates first before coyping to sheet trades
//load current trades on sheet in temp array
var lastRow = first.getLastRow();
var array_from_sheet = first.getRange('A2:E' + lastRow).getValues();
Logger.log("array-from-sheet: ");
Logger.log(array_from_sheet);
//append new trades array to array_from_sheet
trades.splice(1, 0, array_from_sheet);
Solved:
I used this command:
trades_new = array_from_sheet.concat(trades);
instead of:
trades.splice(1, 0, array_from_sheet);
now trades_new contains the 2 arrays end to end.

JavaScript Reformatting JSON arrays

I am relatively new to the JSON notation, and have run into an issue when attempting to reformat. The current format contained in the database needs to be modified to a new format for importation into a project timeline graph.
Here is the current JSON format:
[
{
"name":"5-HP-N/A-N/A-F8",
"node":{
"name":"5",
"id":14
},
"timeline":{
"epc":null,
"m1":null,
"m2":null,
"m3":1554087600000,
"m4":1593572400000,
"m5":1625108400000,
"m6":1641006000000,
"m7":1656644400000
},
"fab":{
"name":"F8",
"id":1
}
},
However, in order to display in the graph, I need the following format:
{
'start': new Date(value from epc, or first non-null milestone),
'end': new Date(value from m1 or first non-null milestone), // end is optional
'content': 'label from start Date milestone'
'group' : ' value from name field above 5-HP'
'classname' : ' value from start Date milestone'
});
I am trying to write a function in order to accomplish this. Only epc, m1, or m2 may have the value of null, but the condition must be checked for to determine if an event range should be created and where it should end. What would be the best way to reformat this json data (preferrably from an external json sheet)?
Edit: Thanks for all the help I see how this is working now! I believe I didn't explain very well the first time though, I actually need multiple class items per "group".
The end result is that these will display inline on a timeline graph 'group' line, and so I am trying to figure out how to create multiple new objects per array element shown above.
So technically, the first one will have start date = m3, and end date = m4. Then, the next object would have the same group as the first (5-HP...), the start date = m4, end date = m5...etc. This would continue until m7 (always an end date but never a start date) is reached.
This is why the loop is not so simple, as many conditions to check.
see a working fiddle here: http://jsfiddle.net/K37Fa/
your input-data seems to be an array, so i build a loop around that. if not just see this fiddle where the input data is a simple object: http://jsfiddle.net/K37Fa/1/
var i
, result = [],
, current
, propCounter
, content = [ { "name":"5-HP-N/A-N/A-F8", "node":{ "name":"5", "id":14 }, "timeline":{ "epc":null, "m1":null, "m2":null, "m3":1554087600000, "m4":1593572400000, "m5":1625108400000, "m6":1641006000000, "m7":1656644400000 }, "fab":{ "name":"F8", "id":1 } }],
// get the milestone in a function
getMileStone = function(obj) {
propCounter = 1;
for(propCounter = 1; propCounter <= 7; propCounter++) {
// if m1, m2 and so on exists, return that value
if(obj.timeline["m" + propCounter]) {
return {key: "m" + propCounter, value: obj.timeline["m" + propCounter]};
}
}
};
// loop over content array (seems like you have an array of objects)
for(i=0;i< content.length;i++) {
current = content[i];
firstMileStone = getMileStone(current);
result.push({
'start': new Date(current.epc || firstMileStone.value),
'end': new Date(current.m1 || firstMileStone.value),
'content': firstMileStone.key,
'group' : current.name,
'classname' : firstMileStone.value
});
}
EDIT:
getMileStone is just a helper-function, so you could just call it with whatever you want. e.g. current[i+1]:
secondMileStone = getMileStone(current[i + 1])
you should just check, if you are not already at the last element of your array. if so current[i+1] is undefined, and the helperfunction should return undefined.
you could then use as fallback the firstMileStone:
secondMileStone = getMileStone(current[i + 1]) || firstMileStone;
see the updated fiddle (including check in the getMileStone-Helperfunction): http://jsfiddle.net/K37Fa/6/

How do i reverse JSON in JavaScript?

[
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
]
I looked on here, and someone had the same sort of question, but the "checked" correct answer was that it will be different on IE if the item is deleted, which would be fine. My issue is, those items above are stored, but when i go and grab them, iterate, and return, the items are reversed and the created is at the 0 index and task is at 1. Also, i need to return this as JSON.
Here is my basic JS (value == an int the user is passing in):
outputJSON = {};
for(x in json[value]){
outputJSON[x] = _objectRevival(json[value][x]);
}
return outputJSON;
That returns:
created: Mon Dec 06 2010 15:09:40 GMT-0800 (Pacific Standard Time)
task: "test"
The order of the properties of an object is undefined. It is not possible to force them in a specified order. If you need them in a specific order, you can build this structure reliably using arrays:
var values = [
[["task", "test"], ["created", "/Date(1291676980607)/"]],
[["task", "One More Big Test"], ["created", "/Date(1291677246057)/"]],
[["task", "New Task"], ["created", "/Date(1291747764564)/"]]
];
Then you can iterate over your structure like this:
for (var i = 0; i < values.length; i++) {
for (var k = 0; k < values[i]; k++) {
// values[i][k][0] contains the label (index 0)
// values[i][k][1] contains the value (index 1)
}
}
To enforce a particular order for your output just replace json[value] in your for loop with an array of the object properties in the order you want to display them, in your case ["task", "created"].
The problem is that javascript objects don't store their properties in a specific order. Arrays on the other do (hence why you can get something consistent from json[0], json[1], json[2]).
If your objects will always have "task" and "created", then you can get at them in any order you want.
json[value]["task"]
and
json[value]["created"]
Update:
This should work with your existing code.
Before sending the json object:
var before = [
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
];
var order = [];
for (var name in before[0]) {
order.push(name); // puts "task", then "created" into order (for this example)
}
Then send your json off to the server. Later when you get the data back from the server:
var outputJSON = {};
for (var x in order) {
if (order.hasOwnProperty(x)) {
outputJSON[order[x]] = _objectRevival(json[value][order[x]]); // I'm not sure what _objectRevival is...do you need it?
}
}
return outputJSON;
var items = ["bag", "book", "pen", "car"];
items.reverse();
This will result in the following output:
car , pen, book, bag
Even if you have JSON array it will reverse.

Categories

Resources