How can I group by multiple condition in javascript? - javascript

I have the data in the below format:
[
{
"Id": 1,
"Title": "Title_1",
"Positive": 5,
"CreateTs": 1674231433428
},
{
"Id": 2,
"Title": "Title_1",
"Positive": 8,
"CreateTs": 1674288139000
},
{
"Id": 3,
"Title": "Title_2",
"Positive": 5,
"CreateTs": 1674633970000
},
{
"Id": 4,
"Title": "Title_1",
"Positive": 12,
"CreateTs": 1674649613000
},
{
"Id": 5,
"Title": "Title_1",
"Positive": 10,
"CreateTs": 1674649741000
}
]
And I want the result as below:
[
// group by Title, and CreateTs in current week
// Sum up the grouped number of Positive
{
"Title": "Title_1",
"Positive_sum": 22
},
{
"Title": "Title_2",
"Positive_sum": 5
}
]
I found similar question, but I am not able to interrupt it, it is too complex for me...
I tried to use array.slice method and get the first few terms. But it is not guarantee as the data is in different order every time. And I found some complex method on internet and it seems not work for me. So I would like to ask for help here.

function getMonday(d) {
d = new Date(d);
let day = d.getDay(),
diff = d.getDate() - day + (day === 0 ? -6:1); // adjust when day is sunday
return new Date(d.setDate(diff));
}
let result = [{"Title": "Title_1", "Sum": 0}, {"Title": "Title_2", "Sum": 0}];
let NOW = Math.floor(new Date(getMonday(new Date())).getTime() / 1000);
data.forEach(elm => {
if (elm.Title === result[0].Title && elm.CreateTs > NOW) {
result[0].Sum += elm.Positive;
}
if (elm.Title === result[1].Title && elm.CreateTs > NOW) {
result[1].Sum += elm.Positive;
}
});
Here is a code that will verify the title of your object and check if the timestamp is superiror to the Monday of the week.

First we need to filter to get current week start timestamp and end timestamp
and we can filter CreateTs with that
Then we can use reduce to group our objects we use object instead of array because it is easier as you see, then we can use values() to convert obj to arr
const now = new Date();
const currentWeekStart = new Date(now.getFullYear(), now.getMonth(), now.getDate() - now.getUTCDay());
const currentWeekEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() + (6 - now.getUTCDay()));
const result = data
.filter((item) => {
const date = new Date(item.CreateTs);
return date >= currentWeekStart && date <= currentWeekEnd;
})
.reduce((acc, item) => {
const { Title, Positive } = item;
if (!acc[Title]) {
acc[Title] = { Title, Positive_sum: Positive };
} else {
acc[Title].Positive_sum += Positive;
}
return acc;
}, {});
console.log(Object.values(result));

Related

How to filter if there is a value inside the array and if there is not

"periodos": [
{
"id": 3,
"transporte_id": 2,
"ativo": 1,
"periodo": "MANH\u00c3",
"corte": "12:00",
"data": null,
"week": [0, 1, 1, 1, 1, 1, 1]
},
{
"id": 4,
"transporte_id": 2,
"ativo": 1,
"periodo": "TARDE",
"corte": "18:00",
"data": null,
"week": [0, 1, 1, 1, 1, 1, 1]
},
{
"id": 7,
"transporte_id": 2,
"ativo": 1,
"periodo": "PERIODO PARA O DIA 16",
"corte": "10:00",
"data": "2022-12-16",
"week": [0, 1, 1, 1, 1, 1, 1]
}
]
I have this array, if the date object is different from null, I would like it to make a filter confirming whether the selected date is equal to today's date, if so, it returns the object that is equal to today's date
if the date is null or is not equal to today, it returns this filter
return this.periodos.filter( transpId => transpId.ativo === (1) && transpId.transporte_id === (this.metodoId) && transpId.week[d.getDay()] === 1 ) ;
I would like to put the code inside my function that already exists
filterPeriodos() {
const object = this.formGeral.value.data;
const jsDate = new Date(object.singleDate?.jsDate);
jsDate.setUTCHours(23, 59, 59, 999);
this.dataFormat = jsDate;
const d = new Date(jsDate );
if (this.storeS.layout.emp.id === 1) {
if (this.formGeral.value.entregaBool){
return this.periodos.filter( transpId => transpId.ativo === (1) && transpId.transporte_id === (this.metodoId) && transpId.week[d.getDay()] === 1 ) ;
}
}
return this.periodos;
}
I tried putting an if conditional inside my this.periodos.filter, but I didn't succeed
You can do it like so:
const arr=[{id:3,transporte_id:2,ativo:1,periodo:"MANHÃ",corte:"12:00",data:null,week:[0,1,1,1,1,1,1]},{id:4,transporte_id:2,ativo:1,periodo:"TARDE",corte:"18:00",data:null,week:[0,1,1,1,1,1,1]},{id:7,transporte_id:2,ativo:1,periodo:"PERIODO PARA O DIA 16",corte:"10:00",data:"2022-12-16",week:[0,1,1,1,1,1,1]}];
let currentDate = new Date()
let query = `${currentDate.getFullYear()}-${currentDate.getMonth() + 1}-${currentDate.getDate()}`
const result = arr.filter(e => e.data == query)
console.log(result)
Simply get the current date and construct the query in the right format, then filter with it.

momentjs iterate over dates in a two week period and map the date to existing array

I have an array that has a object with two properties, 'location' and 'needs'. The needs property has an array of objects with a date and count {date: "2021-06-15", count: 10} so an array would look like this:
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
What I need to do is to use Momentjs to use today's date, figure out the two week period starting from today, and then map the needs-count to the date in the moment loop. If there is a date missing (like in the example below), it should put a 0 as the count
A final array would look like...
{
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56 // this had a count in the initial object
},
{
"date": "2021-04-07",
"count": 0
},
{
"date": "2021-04-08",
"count": 0
},
{
"date": "2021-04-09",
"count": 0
},
{
"date": "2021-04-10",
"count": 0
},
{
"date": "2021-04-11",
"count": 0
},
{
"date": "2021-04-12",
"count": 0
},
{
"date": "2021-04-13",
"count": 10 // this had a count in the initial object
},
...
...
...
]
}
In terms of a function, the closest I have got is
let startDay = moment().format('YYYY-MM-DD');
let endDay = moment().add(14, 'days').format('YYYY-MM-DD');
let startDate = moment(startDay);
let endDate = moment(endDay);
let datesBetween = [];
let startingMoment = startDate;
while(startingMoment <= endDate) {
for (let count = 0; count < 15; count ++) {
// at this point im trying to take 'week' which has the location property and needs property and trying to merge them together... but failed miserably.
if (week.needs[count].date === startingMoment) {
datesBetween.push([startingMoment.clone(), week.needs[count].count]);// clone to add new object
startingMoment.add(1, 'days');
} else {
datesBetween.push([startingMoment.clone(), 0]);// clone to add new object
}
}
}
Can someone see where I went so wrong?
const week = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
}
let current = moment();
const allDates = [];
const FORMAT = 'YYYY-MM-DD';
for (let count = 0; count < 14; count++) {
const found = week.needs.find(i => i.date === current.format(FORMAT));
if (found) {
allDates.push(found);
} else {
allDates.push({
date: current.format(FORMAT),
count: 0,
});
}
current.add(1, 'day');
}
week.needs = allDates;
console.log(week);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script>
You could do something like this :
let dates = {
"location": "NYC",
"needs": [
{
"date": "2021-04-06",
"count": 56
},
{
"date": "2021-04-13",
"count": 10
}
]
};
let day = moment();
for( let i=0; i< 15; i++){
let date = day.add(1, "days").format("YYYY-MM-DD");
console.log(`Looking if ${date} is in array...`)
if(dates.needs.find(obj => obj.date === date)) continue;
console.log(`Adding ${date}`)
dates.needs.push({ date, count : 0 })
}
dates.needs.sort( (a,b) => a.date > b.date ? 1: -1 );
console.log(dates)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Get items for today and yesterday based off timestamp

I have a json object which is generated using lowdb. Each json entry has a timestamp. I wan't to get all the entry for yesterday, and today based on the timestamp.
The items variable here is just a json object. Here is a sample
{
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
}
I want to get the items from yesterday, and today in this functuin
export async function report(){
try {
const items = db.get('items').value();
return items;
} catch (error) {
console.log(error);
}
}
You can compare with time values for the start of "today" and "yesterday", e.g.
// Return time value for the start of given date, default is today
function getToday(d = new Date()) {
return new Date(+d).setHours(0,0,0,0);
}
// Return time value for the start of day prior to given day, default is today
function getYesterday(d = new Date()) {
let e = new Date(getToday(d));
return e.setDate(e.getDate() - 1);
}
let data = {
"items": [
{"date": 1596085802005, // 30 Jul 2020
"item": "1"
},
{"date": 1596131220030, // 31 Jul 2020
"item": "2"
},
{"date": 1596232321030, // 1 Aug 2020
"item": "3"
}
]
}
// Run as for 1 Aug 2020
let yesterday = getYesterday(new Date(2020,7,1));
let result = data.items.filter(item => item.date >= yesterday);
console.log(result);
Results may vary based on the host timezone offset as the above uses local date values.
You need to parse the date, and compare the difference as follows:
let obj = {
"items": [
{
"date": 1596131220030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
},
{
"date": 1596232321030,
"item": {
"price": "160,00",
"title": "Cotton Quarter-Zip Sweater"
}
}
]
};
let list = [];
let items = obj.items;
let today = new Date();
for(let i = 0; i < items.length; i++){
var d = new Date(items[i].date);
var diff = Math.floor((d - today) / (1000 * 60 * 60 * 24));
if(diff == 0 || diff == -1)
list.push(items[i].item);
}
console.log(list);

Blank data for certain hours - hence missing in my array. Is there a way to fill in the missing hours?

I have some data by the hour and summarise/consolidate the array.
However, there are some hours which are blank in data.Items hence my array would skip the data point completely.
Is there a way where I can through my data/array and fill in the gaps and assign a '0' next to it?
for(i=0; i<dataLength; i++){
var date = new Date(data[i].ctimestamp);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
var date = moment(date).tz("Pacific/Auckland").format("DD/MM/YY HH:mm");
dateArray.push({"date" : date});
}
Here is an example - "11/12/18 05:00" and "11/12/18 06:00" are missing so it's skipped completely.
[{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 04:00",
"count": 6
}]
Ideally, I would like it to show:
[
{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 06:00",
"count": 0
},
{
"date": "11/12/18 05:00",
"count": 0
},
{
"date": "11/12/18 04:00",
"count": 6
}]
I think this simplifies the logic and produces the result you want:
const data = [
{
"date": "11/12/18 08:00",
"count": 5
},
{
"date": "11/12/18 07:00",
"count": 4
},
{
"date": "11/12/18 04:00",
"count": 6
}
];
let min = Number.MAX_VALUE;
let max = 0;
const dates = data.reduce((memo, {date, count}) => {
const time = new Date(date).getTime();
min = Math.min(min, time);
max = Math.max(max, time);
memo[time] = count;
return memo;
}, {});
const ONE_HOUR = 60 * 60 * 1000;
const dataOutput = [];
for (let i = min;i <= max;i += ONE_HOUR) {
dataOutput.push({
date: new Date(i).toLocaleString(),
count: dates[i] || 0
});
}
console.log(dataOutput)
I'll assume the array you posted as sample data, is called dataItems. Also, I'll use moment to handle time, but you can convert it to vanilla JS if you want.
So, what I would do is go through dataItems, and check if prev value is 1 hour prev to this value, if its not, add a new input.
dataItems.reduce((acc, val) => {
if(!acc) {
return [moment(val)];
}
let momentVal = moment(val)
if (momentVal.diff(acc[acc.length - 1], 'hours') !== 1){
acc.push(momentVal)
return acc;
} else {
while(momentVal.diff(acc[acc.length - 1], 'hours') !== 1){
acc.push(moment(acc[acc.length - 1]).add(1, 'hours')) //clone and add 1 hour
}
}
}])
I didn't take in consideration your object isn't just date, but that should be simple to adapt. The general logic is: go through your array, if the previous one is 1 hour less than right now, keep it going. Else, add a new input until the actual one is 1 hour after the last one on the array

How do I change date formatting in Javascript to enable sorting?

I am writing my dates of birth in the following manner:
4.02.1976 14:37
1.7.1990 11:35
10.10.1910 18:00
I wanted to sort it using something similar to this code (enabling sorting by birth):
var obj = [{"id":1,"dateOfBirth":"1.7.1990 11:35"},
{"id":4,"dateOfBirth":"4.02.1976 14:37"},{"id":2,"dateOfBirth":"28.10.1950
2:15"},{"id":3,"dateOfBirth":"03.01.1963 23:10"}]
obj.sort(function(a,b) { return new Date(a.dateOfBirth).getTime() - new
Date(b.dateOfBirth).getTime() } );
I am unsure if I need to reformat the dates of birth to achieve this.
Since you just have the year/month/day, it's pretty trivial to split up the dateOfBirth string, convert to a single number, and sort by that number, without any need to mess with Dates:
var obj = [{
"id": 1,
"dateOfBirth": "1.7.1990"
}, {
id: 2,
dateOfBirth: "28.10.1950"
}, {
"id": 4,
"dateOfBirth": "4.02.1976"
}];
function valueFromDOBString(str) {
const values = str.split('.').map(Number);
return values[0] + values[1] * 100 + values[2] * 10000;
}
const sortedObj = obj.sort((a, b) => {
return valueFromDOBString(b.dateOfBirth) - valueFromDOBString(a.dateOfBirth);
});
console.log(sortedObj);
A working version with optional time values.
var obj = [{
"id": 1,
"dateOfBirth": "1.7.1990"
},
{
"id": 4,
"dateOfBirth": "4.02.1976 14:37"
}, {
"id": 2,
"dateOfBirth": "28.10.1950 2:15"
}
];
console.log(
obj.sort(function(a, b) {
return parseDate(a.dateOfBirth) -
parseDate(b.dateOfBirth);
})
);
function parseDate(str) {
var tokens = str.split(/\D/);
while (tokens.length < 5)
tokens.push(0);
return new Date(tokens[2], tokens[1]-1, tokens[0], tokens[3]||0, tokens[4]||0);
}

Categories