How to merge duplicate object parent items in array? - javascript

I want to merge objects in array so that objects with the same id (which is a child object) can sum the total_price and total_quantity values.
Here is my data array:
var data = [
{
"_id": {
"month": 5,
"year": 2021
},
"total_price": 145111500,
"total_quantity": 7
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 98386000,
"total_quantity": 5
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 32500000,
"total_quantity": 3
}
]
I want to merge objects that have the duplicate "_id". Here is the output result:
var merge = [
{
"_id": {
"month": 5,
"year": 2021
},
"total_price": 145111500,
"total_quantity": 7
},
{
"_id": {
"month": 6,
"year": 2021
},
"total_price": 130886000,
"total_quantity": 8
}
]
Thanks in advance.

const data = [
{ "_id": { "month": 5, "year": 2021 }, "total_price": 145111500, "total_quantity": 7 },
{ "_id": { "month": 6, "year": 2021 }, "total_price": 98386000, "total_quantity": 5 },
{ "_id": { "month": 6, "year": 2021 }, "total_price": 32500000, "total_quantity": 3 }
];
const res = [...
// iterate over the list
data.reduce((map, item) => {
// construct key from _id
const key = `${item._id.month}-${item._id.year}`;
// get prev map value of key if exists
const prev = map.get(key);
// update map, if prev not found, set value as item, or update it with the added values
map.set(
key,
!prev
? item
: { ...item, total_price: prev.total_price + item.total_price, total_quantity: prev.total_quantity + item.total_quantity }
);
return map;
}, new Map)
// return map values
.values()
];
console.log(res);

var ids = [];
var merge = [];
for (let i = 0; i < data.length; i++) {
obj = data[i];
let dupId = false;
for (let j = 0; j < ids.length; j++) {
if (ids[j]["month"] == obj["_id"]["month"] && ids[j]["year"] == obj["_id"]["year"]) {
merge[j]["total_price"] += obj["total_price"];
merge[j]["total_quantity"] += obj["total_quantity"];
dupId = true;
break;
}
}
if (!dupId) {
ids.push(obj["_id"]);
merge.push(obj);
}
}
The code will:
Declare and initialize merge array to an empty array
Loop through all elements from data array
And inside, check for duplicate of element in merge array
If found, add total quantities and total prices
If not found, add element to merge array

Related

Filter an array of objects with latest date if array contains same date with different timestamp in multiple objects

I have an array of objects and each object has the date. I need to filter the array and get the objects that contains latest date.
[
{
"Id": 25,
"MeasureDate": "2022-08-26T00:01:01.001Z"
},
{
"Id": 26,
"MeasureDate": "2022-08-26T11:10:01.001Z"
},
{
"Id": 27,
"MeasureDate": "2022-08-26T16:12:01.001Z"
},
{
"Id": 30,
"MeasureDate": "2022-08-27T00:08:01.001Z"
},
{
"Id": 31,
"MeasureDate": "2022-08-27T10:20:10.001Z"
}
]
After filtering the array I need the array should look like below
[
{
"Id": 27,
"MeasureDate": "2022-08-26T16:12:01.001Z"
},
{
"Id": 31,
"MeasureDate": "2022-08-27T10:20:10.001Z"
}
]
const dateItems = [
{
"Id": 25,
"MeasureDate": "2022-08-26T00:01:01.001Z"
},
{
"Id": 26,
"MeasureDate": "2022-08-26T11:10:01.001Z"
},
{
"Id": 27,
"MeasureDate": "2022-08-26T16:12:01.001Z"
},
{
"Id": 30,
"MeasureDate": "2022-08-27T00:08:01.001Z"
},
{
"Id": 31,
"MeasureDate": "2022-08-27T10:20:10.001Z"
}
];
// As we loop through your dateItems array we need to keep track of the Latest DateTime for each day
// Probably the easiest way is to create a key on a property for each date and then attach the object
// from your array to that key if it is the first for that date or later than an existing one.
const latestDateTimesByDate = {};
dateItems.forEach( di => {
// Use the date part of the date time as a key/ property name on the latestDateTimesByDate object
let dateKey = di.MeasureDate.substring(0, 10);
// If that date key doesnt exist or the current MeasureDate is gretaer than the recorded one
if( !latestDateTimesByDate[dateKey] || di.MeasureDate > latestDateTimesByDate[dateKey].MeasureDate) {
latestDateTimesByDate[dateKey] = di;
}
});
// if you need it as an array then add each of the date properties to an element of an array
const finalArray = [];
Object.keys(latestDateTimesByDate).forEach( key => finalArray.push(latestDateTimesByDate[key]));
Here's a solution for your probleme :
function similarDates(obj){
date_obj = new Date(obj.MeasureDate);
// Getting only the dates with same year, month, day
let sim_dates = popo.filter((objs) => {
date = new Date(objs.MeasureDate)
return date.toDateString() === date_obj.toDateString()
});
// Returning the similare dates
return sim_dates
}
function filterData(array) {
result = []
while(array.length) {
console.log(array)
var sameElement = similarDates(array[0]);
// removing all the treated elements from the array
array = array.filter( ( el ) => !sameElement.includes(el));
result.push(sameElement.sort((a, b) => new Date(b.MeasureDate) - new Date(a.MeasureDate)).shift());
}
return result;
}

How to find array of object if current value more closest to now date?

I have JSON file that contain year value in string in edu_end_year. I want to choose one if the data more than one in same emp_id when the edu_end_year is closest to date now.
here's the data:
educations = [
{
"emp_id": 1,
"edu_degree": "SMA",
"edu_end_year": 2011
},
{
"emp_id": 1,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
}
]
here's result what i expected :
[
{
"emp_id": 1,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
}
]
I was trying using filter() and find(), but still no luck.
please let me know if you need more information to solve that problem if it's still not enough.
One way to solve this would be to use a Map and store the education with the highest edu_end_year for each emp_id.
const maxEducations = new Map();
for (const education of educations) {
const maxEducation = maxEducations.get(education.emp_id);
if (maxEducation && education.edu_end_year <= maxEducation.edu_end_year) continue;
maxEducations.set(education.emp_id, education);
}
The if-statment will skip the rest of the iteration if maxEducation is found and the current education.edu_end_year less or equal to maxEducation.edu_end_year.
If either maxEducation is not set, or we encounter a new max edu_end_year then the current education is set as the new maximum.
Once you've iterated through all educations and you'd like to have an array of the values, you can do the following
const result = Array.from(maxEducations.values());
const educations = [
{
"emp_id": 1,
"edu_degree": "SMA",
"edu_end_year": 2011
},
{
"emp_id": 1,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
}
];
const maxEducations = new Map();
for (const education of educations) {
const maxEducation = maxEducations.get(education.emp_id);
if (maxEducation && education.edu_end_year <= maxEducation.edu_end_year) continue;
maxEducations.set(education.emp_id, education);
}
console.log(Array.from(maxEducations.values()));
I don't know this code efficient to handle big data or not, but that's work to fix if emp_id is same.
suggestion use this code after pagination
educations = [
{
"emp_id": 1,
"edu_degree": "SMA",
"edu_end_year": 2011
},
{
"emp_id": 1,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2016
}
]
for (let i = educations.length -1; i > 0; i--){
if(educations[i].emp_id === educations[i-1].emp_id){
educations.splice(i, i)
}
}
console.log(educations)
You can use Array.reduce
use reduce() to loop through each element
Check your final array (acc) has items by checking emp_id into list
If it's first item then insert into
If same emp_id exists then check which year is greater
Replace newer year record into final array
educations = [
{
"emp_id": 1,
"edu_degree": "SMA",
"edu_end_year": 2011
},
{
"emp_id": 1,
"edu_degree": "S1",
"edu_end_year": 2016
},
{
"emp_id": 2,
"edu_degree": "S1",
"edu_end_year": 2015
},
{
"emp_id": 2,
"edu_degree": "S13",
"edu_end_year": 2017
},
{
"emp_id": 2,
"edu_degree": "S14",
"edu_end_year": 2016
}
]
finalArr = educations.reduce((acc, prev) => {
if(!acc.find(x=>x.emp_id === prev.emp_id)){
acc.push(prev)
}
else{
let record = acc.find(x=>x.emp_id === prev.emp_id);
if(prev.edu_end_year >= record.edu_end_year){
let index = acc.findIndex(x=>x.emp_id === prev.emp_id);
acc[index] = prev;
}
}
return acc;
}, []);
console.log(finalArr)
This should do it:
const educations = [{"emp_id": 1,"edu_degree": "SMA","edu_end_year": 2011},
{"emp_id": 1,"edu_degree": "S1","edu_end_year": 2016},
{"emp_id": 3,"edu_degree": "S3","edu_end_year": 2014},
{"emp_id": 2,"edu_degree": "S1","edu_end_year": 2016}];
const res=Object.values(educations.reduce((a,c)=>{
if(!a[c.emp_id]||a[c.emp_id].edu_end_year<c.edu_end_year) a[c.emp_id]=c;
return a;
},{}));
console.log(res);
I misunderstood your question at first and changed my answer accordingly now. The above snippet uses a single .reduce() loop to filter out the latest elements for each .emp_id.

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>

How to check the condition the array contains the element in javascript?

Code:
monthArray = ["jan 2009", ..., "dec 2009"];
The jsonFile contains:
[
{
"month": "Aug 2012",
"no_Of_Commits": 1
},
{
"month": "Jun 2012",
"no_Of_Commits": 1
},
{
"month": "Apr 2012",
"no_Of_Commits": 6
}
]
function populate(jsonFile) {
tempJson = jsonFile;
for (var i = 0; i < monthArray.length; i++)
{
if (monthArray.contains(tempJson[i]["month"])) // condition Not working suggest anything else
{
console.log("yes");
tempJson[i]["no_Of_Commits"] = tempJson[i]["no_Of_Commits"];
}
else
{
console.log("NO");
jsonFile[i]["no_Of_Commits"] = 0;
}
}
}
Replace contains with indexOf
if ( monthArray.indexOf( tempJson[i]["month"] ) !== -1 ) {...
and as you're iterating over one array, and getting values from another array, you better make sure both arrays have the same number of indices etc.

How to fill dates in an array containing range of dates?

I have an array of dates containing a count value. e.g.
[
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-13T08:00:00.000Z",
"count": 4
}
{
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
]
How do I fill in the missing dates with count = 0, to produce the following in javascript:
[
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-12T08:00:00.000Z",
"count": 0
},
{
"date": "2014-11-13T08:00:00.000Z",
"count": 4
},
...
]
as you appear to be using momentjs
the first thing that came to mind was use the moment().add(number, units) and moment().diff(input, units, asFloat)
something like
var data = [
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
}, {
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
];
var startDate = moment(data[0].date);
var endDate = moment(data[1].date);
var days = endDate.diff(startDate, 'd', false);
alert(days);
for (var i = 1; i < days; i++) {
data.splice(i,0, {"date" : startDate.add(1, 'd').toISOString(), 'count': 0 })
}
for (var i = 0; i < data.length; i++) {
alert(data[i].date);
}
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
Try this:
var arr = [
{
"date": "2014-11-11T08:00:00.000Z",
"count": 8
},
{
"date": "2014-11-16T08:00:00.000Z",
"count": 4
}
];
function fillDates(start, end) {
var output = [start];
var date = new Date(start.date);
var endDate = new Date(end.date);
do {
output.push({
"date": date.toISOString(),
"count": 0
});
date = new Date(date.getTime());
date.setDate(date.getDate() + 1);
} while (date < endDate);
output.push(end);
return output;
}
var start = arr[0];
var end = arr[1];
fillDates(start, end);
const models = [
{
date: '2018-10-17',
value: 3,
},
{
date: '2018-10-20',
value: 4,
},
{
date: '2018-10-21',
value: 5,
},
{
date: '2018-10-27',
value: 6,
},
];
const filledInDates = models.reduce((newArray, currentModel, index, originalArray) => {
const nextModel = originalArray[index + 1];
if (nextModel) {
const currentDate = moment(currentModel.date);
const daysBetween = moment(nextModel.date).diff(currentDate, 'days');
const fillerDates = Array.from({length: daysBetween - 1}, (value, dayIndex) => {
return {
value: currentModel.value,
date: moment(currentDate).add(dayIndex + 1, 'days').format('YYYY-MM-DD'),
};
});
newArray.push(currentModel, ...fillerDates);
} else {
newArray.push(currentModel);
}
return newArray;
}, []);
console.log(filledInDates);
Output:
[
{value:3, date:"2018-10-17"},
{value:3, date:"2018-10-18"},
{value:3, date:"2018-10-19"},
{value:4, date:"2018-10-20"},
{value:5, date:"2018-10-21"},
{value:5, date:"2018-10-22"},
{value:5, date:"2018-10-23"},
{value:5, date:"2018-10-24"},
{value:5, date:"2018-10-25"},
{value:5, date:"2018-10-26"},
{value:6, date:"2018-10-27"}
]

Categories