Related
I have the following json file
[{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}]
I want to add new items using JavaScript, jquery, to end up with
[{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-02T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-03T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-04T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-06T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-07T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-09T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-10T00:00:00","orders":0},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}]
maybe by calculating the number of missed items between dates, or just calculating the diff between the numbers represents the day i.e: "2019-02-01T00:00:00" and "2019-02-05T00:00:00" then add 3 items?
var items = [
{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},
{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},
{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},
{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}
]
var newItems = []
for(var i = 0; i < items.length; i++){
newItems.push(items[i])
var currentDay = moment(items[i].mov_date)
var nextDay = currentDay.add(1, 'days');
if(typeof items[i+1] !== 'undefined'){
var diff = moment(items[i+1].mov_date).diff(currentDay, 'days')
for(var j = 1; j <= diff; j++){
var newItem = JSON.parse(JSON.stringify(items[i]))
newItem.mov_date = moment(items[i].mov_date).add(j, 'days').utc(false).format();
newItem.orders = 0
newItems.push(newItem)
}
}
}
console.log(newItems)
<script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>
Check also this one that uses reduce() preserving all the props(including id) and only resetting orders and setting correct mov_date in between.
var items = [{
"id": 5,
"num": "n61",
"mov_date": "2019-02-01T00:00:00",
"orders": 19
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-05T00:00:00",
"orders": 12
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-08T00:00:00",
"orders": 5
},
{
"id": 5,
"num": "n61",
"mov_date": "2019-02-11T00:00:00",
"orders": 7
}
]
const newItems = items.reduce((acc, next) => {
// first run with early return
if (!acc.length) {
return [...acc, next]
}
// taking the recent item, to preserve the id and other props
const prevItem = acc[acc.length - 1];
// getting diff in days - 1
const days = moment.utc(next.mov_date).diff(moment.utc(prevItem.mov_date), 'days') - 1;
// [...Array] is a trick to get mappable arrays without array holes,
// but with initialized undefined values,
// so we can get the index during map
const inBetweenValues = [...Array(days)].map((_, dayIndex) => {
return {
...prevItem,
orders: 0,
mov_date: moment.utc(prevItem.mov_date).add(dayIndex + 1, 'days').format()
};
});
// merging it all, and moving to the next loop
return [...acc, ...inBetweenValues, next];
}, [])
console.log(newItems);
<script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>
You could use a Date object which you increment using its setDate method, and which you render to string with toJSON. Then when the date string matches the next entry, you copy it, otherwise you duplicate it with orders: 0:
const data = [{"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19},{"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12},{"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5},{"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7}];
const end = new Date(data[data.length-1].mov_date + "Z");
const result = [];
for (let dt = new Date(data[0].mov_date+"Z"), i = 0; dt <= end; dt.setUTCDate(dt.getUTCDate()+1)) {
result.push({...data[i], ...(dt.toJSON().slice(0,19) === data[i].mov_date ? (i++, {}) : { orders: 0 })});
}
console.log(result);
Here is an algorithm that will do That for you. I used
Convert JS date time to MySQL datetime for date conversion.
function twoDigits(d) {
if(0 <= d && d < 10) return "0" + d.toString();
if(-10 < d && d < 0) return "-0" + (-1*d).toString();
return d.toString();
}
function toMysqlFormat() {
return this.getUTCFullYear() + "-" + twoDigits(1 + this.getUTCMonth()) + "-" + twoDigits(this.getUTCDate()) + "T" + twoDigits(this.getUTCHours()) + ":" + twoDigits(this.getUTCMinutes()) + ":" + twoDigits(this.getUTCSeconds());
};
var prev = 0;
for( var x = 1; x < obj.length; x++ ){
if( !obj[x -1].mov_date ){
continue;
}
var tx = Date.parse( obj[x-1].mov_date );
var diff = ( Date.parse(obj[x].mov_date ) - tx ) / (1000*24*60*60);
for( var y = 1; y < diff; y++ ){
obj.splice( x - 1 + y,0, { "id" : 5, "num" : "n61", "mov_date" : toMysqlFormat.bind( new Date( tx + ( y*1000*24*60*60) ) )(), "orders" : 0} );
}
x += diff - 1;
}
for( var x = 0; x < obj.length; x++ ){
console.log( JSON.stringify( obj[x] ) );
}
/* Result :
/* {"id":5,"num":"n61","mov_date":"2019-02-01T00:00:00","orders":19} */
/* {"id":5,"num":"n61","mov_date":"2019-02-02T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-03T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-04T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-05T00:00:00","orders":12} */
/* {"id":5,"num":"n61","mov_date":"2019-02-06T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-07T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-08T00:00:00","orders":5} */
/* {"id":5,"num":"n61","mov_date":"2019-02-09T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-10T00:00:00","orders":0} */
/* {"id":5,"num":"n61","mov_date":"2019-02-11T00:00:00","orders":7} */
*/
I am trying to extract data from one object, restructure and create a new one.
Simplified example for the source object
var res = [{
DateTime: '00:00',
Number: 1,
WeekDay: 1
},
{
DateTime: '00:00',
Number: 4,
WeekDay: 1
},
{
DateTime: '00:00',
Number: 1,
WeekDay: 2
},
{
DateTime: '00:30',
Number: 1,
WeekDay: 2
}]
From here I want to create a new object where "number" is summed by
1. WeekDay
2. Half hour interval
var intervals = ['00:00', '00:30']
var weekdays = [1, 2]
var target = []
var intervalObj = [];
for (i = 0; i < intervals.length; i++) {
intervalObj.push({
interval: intervals[i],
number: 0
})
}
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: intervalObj,
})
}
And then populate the new object like this:
for(var row in res) {
var dt = res[row].DateTime;
var wd = res[row].WeekDay;
var wdidx = weekdays.indexOf(wd)
var dtidx = intervals.indexOf(dt)
var num = res[row].Number;
target[wdidx].data[dtidx].number += num;
}
This does not work when creating the target object like above. The summed results gets repeated for the same interval over all week days.
However, when object is statically:
var target = [{
day: 1,
data: [{
interval: '00:00',
number: 0
},
{
interval: '00:30',
number: 0
}]
},
{
day: 2,
data: [{
interval: '00:00',
number: 0
},
{
interval: '00:30',
number: 0
}]
}]
It works as expected. I cannot figure out why.
Here is a fiddle example:
https://jsfiddle.net/oceansmoving/wkfL9e3o/
You are using the same array reference intervalObj for data in each instance of loop. Need to create new array for each instance
Change
var intervalObj = [];
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: intervalObj,
})
}
To
//var intervalObj = [];
for (i = 0; i < weekdays.length; i++) {
var day = i + 1;
target.push({
day: day,
data: [],
})
}
I’m having a lot of trouble learning how to use for loops to fill a new variable. As an example say if I have var year = [2010, 2000, 1992]; and var age = [];.
How would I use a for loop to fill in the age variable?
If this is a bad example, don’t use this. I just would like some help with understanding how to fill in empty arrays.
var names = ["Ace", "yoshi", "Lassie"];
var age = [25, 23, 5];
var u24 = [];
for (var i = 0; i < names.length; i++) {
if ([age] < 24) {
u24 += age[i]
console.log("hello " + names + " " + "you are" + age);
}
}
It is better to create objects that contain relevant data. Combining the name and age into a person object would help.
var persons = [
{
name: "Ace",
age: 25
},
{
name: "yoshi",
age: 23
},
{
name: "Lassie",
age: 5
}
];
var u24=[];
for (var i =0; i < persons.length; i++) {
var person = persons[i];
if(person.age < 24){
u24.push(person.age);
console.log("hello " + person.name + " " + "you are " + person.age);
}
}
console.log(u24);
But you can also use forEach like this:
var persons = [
{
name: "Ace",
age: 25
},
{
name: "yoshi",
age: 23
},
{
name: "Lassie",
age: 5
}
];
var u24=[];
persons.forEach(
function(person) {
if(person.age < 24){
u24.push(person.age);
console.log("hello " + person.name + " " + "you are " + person.age);
}
}
);
console.log(u24);
By making objects that include all relevant data your loops will never get out of sync. If you remove a person from the persons array then their name and age will go together.
UPDATE: Using a filter
var persons = [
{
name: "Ace",
age: 25
},
{
name: "yoshi",
age: 23
},
{
name: "Lassie",
age: 5
}
];
var youngPersons = persons.filter(
function(person) {
return (person.age < 24);
}
);
console.log(youngPersons);
Or using an ES6 Arrow Function
var persons = [
{ name: "Ace", age: 25 },
{ name: "yoshi", age: 23 },
{ name: "Lassie", age: 5 }
];
var youngPersons = persons.filter((person) => person.age < 24);
console.log(youngPersons);
This provides back an array of the persons that match your Age under 24 criteria.
If all you want to do is fill in the age array with a loop, you can try this:
let years = [2010, 2000, 1992],
age = [],
d = new Date().getFullYear();
years.forEach(year => age.push(d - year));
console.log(age);
As regards the relationship between age and names, I think Intervalia has explained that.
A working version.
Please compare it with your code to see the differences. Arrays always got me when I was starting out, and the syntax with different across languages, despite the reuse of bracket symbols.. AutoIt language still trips me up :P
var names = ["Ace", "yoshi", "Lassie"];
var age = [25, 23, 5];
//Use array.push() to append values
var u24 = [];
//variable i counts up to names.length
//because i++ means 'add one' to i
for (var i = 0; i < names.length; i++) {
//if ([age] < 24) {u24 += age[i];
//age at the count 'i' (which is
//counting)
//is achieved by array[at_index]
if (age[i] < 24) {
u24.push(age[i]); //add it to the end
console.log("Hello " + names[i] +
", you are " + age[i]);
}
}
I have the following data :
[
{"date":1900,"data":[
{"name":"Blackbird","value":0},
{"name":"Seagull","value":1},
{"name":"Sparrow","value":0}
]},
{"date":1910,"data":[
{"name":"Owl","value":1}
]},
{"date":1920,"data":[
{"name":"Eagle","value":0},
{"name":"Albatross","value":2}
]}
]
I need to make an incremental array of arrays from it. It should look something like this :
[
[
{"name":"Blackbird","value":0,"date":1900},
{"name":"Seagull","value":1,"date":1900},
{"name":"Sparrow","value":0,"date":1900}
],
[
{"name":"Blackbird","value":0,"date":1910},
{"name":"Seagull","value":1,"date":1910},
{"name":"Sparrow","value":0,"date":1910},
{"name":"Owl","value":1,"date":1910}
],
[
{"name":"Blackbird","value":0,"date":1920},
{"name":"Seagull","value":1,"date":1920},
{"name":"Sparrow","value":0,"date":1920},
{"name":"Owl","value":1,"date":1920},
{"name":"Eagle","value":0,"date":1920},
{"name":"Albatross","value":2,"date":1920}
]
]
No matter what I have tried, I always end up with all the dates I add to the objects being equal to the last value (1920 here). I understand that the objects are copied by reference only. I have tried using array.map() (like in the answer given here, but my question was not formulated right), but I still get the same problem.
EDIT
Here's one example of code I've tried :
var temp = [];
var b = data.map(function(c, index, main) {
var year = c.date;
temp = [];
main.slice(0, index + 1).map(function(d){
var t = d.data.map(function(e){
e.date = year;
return e;
});
temp = temp.concat(t);
});
return temp;
});
console.log(b);
Here's a working example:
You need to clone the object in order to "break" the reference.
var data = [
{
"date":1900,
"data":[
{"name":"Blackbird","value":0},
{"name":"Seagull","value":1},
{"name":"Sparrow","value":0}
]
},
{
"date":1910,
"data":[
{"name":"Owl","value":1}
]
},
{
"date":1920,
"data":[
{"name":"Eagle","value":0},
{"name":"Albatross","value":2}
]
}
];
var incremental = [];
var dataHistory = null;
for(i = 0; i < data.length; i++){
var temp = dataHistory ? dataHistory.slice() : []; //.slice to clone array
//Replace all values with current date.
for(var j = 0; j < temp.length; j++){
temp[j] = JSON.parse(JSON.stringify(temp[j])); //Clone object
temp[j].date = data[i].date;
}
//Add current date to object.
for(var j = 0; j < data[i].data.length; j++){
var aux = {
name: data[i].data[j].name,
value: data[i].data[j].value,
date: data[i].date
};
temp.push(aux);
}
dataHistory = temp;
incremental.push(temp);
}
document.body.innerHTML = '<pre>' + JSON.stringify(incremental, null, 4) + '</pre>';
If you're using jQuery you can replace:
temp[j] = JSON.parse(JSON.stringify(temp[j]));
With:
temp[j] = $.extend({}, temp[j]);
Try this one:
var data = [
{"date":1900,"data":[
{"name":"Blackbird","value":0},
{"name":"Seagull","value":1},
{"name":"Sparrow","value":0}
]},
{"date":1910,"data":[
{"name":"Owl","value":1}
]},
{"date":1920,"data":[
{"name":"Eagle","value":0},
{"name":"Albatross","value":2}
]}
];
var result = data.map(function(item) {
var replacement = [];
for (var key in item.data) {
var subItem = item.data[key];
subItem.date = item.date;
replacement.push(subItem);
}
return replacement;
});
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 3) + '</pre>';
Use map, iterate over the inner array, and set the date property to each object etc.
var data = [
{"date":1900,"data":[
{"name":"Blackbird","value":0},
{"name":"Seagull","value":1},
{"name":"Sparrow","value":0}
]},
{"date":1910,"data":[
{"name":"Owl","value":1}
]},
{"date":1920,"data":[
{"name":"Eagle","value":0},
{"name":"Albatross","value":2}
]}
]
data = data.map(function(obj, i, arr) {
var o = [];
arr.slice(0, i).forEach(function(item) {
item.data.forEach(function(data) {
o.push(Object.assign({}, data))
});
});
return o.concat(obj.data.map(function(item) { item.date = obj.date; return item }));
});
document.body.innerHTML = '<pre>' + JSON.stringify(data, null, 4) + '</pre>';
Object.assign with polyfill
I have array with a few hundred events where every has date entry (in Date().getTime format in DB) and I have 10 days displayed in simple table. To every day-row I need to display number of events in that particular day. What would be the best way to do that?
Okay here is an update:
I've Firebase db with this structure:
{
events: {
event1: {
date: 144335265211,
title: "sometext",
text: "longer text"
},
event2: {
date: 1444482619766,
title: "sometext",
text: "longer text"
}
}
}
I am pulling it into local Redux store so I have an JS array with the same structure.
This way I am creating the table for particular days:
for (let dc = 0; dc < 10; dc++) {
const date = new Date();
date.setDate(date.getDate() + dc);
const m = date.getMonth();
const d = date.getDay();
const y = date.getUTCFullYear();
rows.push(
<td>"On the " + m + "/" + d + "/" + y + " is SOMENUMBER events"</td>
);
return rows;
}
Thanks a lot!
First you need to convert it to an array:
var events = Object.keys(obj).map((key) => {
return Object.assign({}, obj[key], {eventName: key});
});
Then you need to group them by date. We can do this with lodash.
var groupBy = require('lodash/collection/groupBy');
var eventsWithDay = events.map((event) => {
return Object.assign({}, event, {day: new Date(event.date).setHours(0, 0, 0, 0))
});
var byDay = groupBy(eventsWithDay, 'day');
And byDay will be an object with a key for each date with a value of an array of events for that day.