I have below array of objects,
[{
a: 1,
created_on: '2021-04-23 10:00:01',
}, {
b: 1,
created_on: '2021-04-24 09:03:01',
}, {
b: 1,
created_on: '2021-04-24 13:03:01',
}]
First, I need to group by with date ignoring times.
So,
{
"2021-04-23": [{
a: 1,
created_on: '2021-04-23 10:00:01',
}],
....
}
If it were a date like created_on: '2021-04-23'
, I could use lodash/groupBy
.
I still could use it but now it involves some condition to be applied to convert those created_on
into date format.
Further, I also need to group by those each grouped by date result as such that their created_on
falls within a time interval.
"SALES_SLOTS": [
{
"slot": "00:00-04:00"
},
{
"slot": "04:00-08:00"
},
{
"slot":"08:00-12:00"
},
{
"slot":"12:00-16:00"
},
{
"slot":"16:00-20:00"
},
{
"slot":"20:00-24:00"
}
],
So, if created_on: '2021-04-23 10:00:01'
, it should come in the group,
{
"08:00-12:00": [{
a: 1,
created_on: '2021-04-23 10:00:01',
}]
}
So, first results should be grouped by date from created on and then elements in each groups should be further group by defined time slots.
I suppose, if I could use group by condition, I could achieve the desired result.
Here's how you would use array.groupBy () to create the same grouping by category: Try the demo. products.groupBy (product => {...}) returns an object where each property has the key as category name and value as an array with the products from the corresponding category.
The Group-Object cmdlet displays objects in groups based on the value of a specified property. Group-Object returns a table with one row for each property value and a column that displays the number of items with that value. If you specify more than one property, Group-Object first groups them by the values of the first property, and then, ...
If you want to easily group the items of an array (similarly to GROUP BY in SQL), then welcome the new methods array.groupBy () and array.groupByToMap (). Both functions accept a callback that should return the key of the group where the current items must be inserted.
When grouping objects of different .NET Core types, Group-Object uses the following rules: Same Property Names and Types. If the objects have a property with the specified name, and the property values have the same .NET Core type, the property values are grouped by using the same rules that would be used for objects of the same type.
Array#reduce
with Map
.Grouping by date is fairly simple, you can group the data by created_on.slice(0, 10)
using a Map
.
Then I've created a helper function getSlot
that returns a slot based on the time passed. Now, since your slots are fairly wide, testing just the hour part would be sufficient.
Next, for every group of date, again group it by time using getSlot
helper and Map
and using Object.fromEntries
you can get the desired object.
NOTE: I've used expressions instead of statements inside my code (using commas, defaulted parameters) which is just a preferential choice.
const
arr = [{ a: 1, created_on: "2021-04-23 10:00:01" }, { b: 1, created_on: "2021-04-24 09:03:01" }, { b: 1, created_on: "2021-04-24 13:03:01" }],
slots = [{ slot: "00:00-04:00" }, { slot: "04:00-08:00" }, { slot: "08:00-12:00" }, { slot: "12:00-16:00" }, { slot: "16:00-20:00" }, { slot: "20:00-24:00" }],
grpDate = Array.from(
arr.reduce(
(m, o, _i, _arr, d = o.created_on.slice(0, 10)) => (
m.has(d) ? m.get(d).push(o) : m.set(d, [o]), m
),
new Map()
)
),
getSlot = (time) =>
slots
.find(({ slot }) => time >= slot.slice(0, 2) && time < slot.slice(6, 8))
.slot,
grpSlot = grpDate.map(([k, v]) =>
[k, Object.fromEntries(v.reduce(
(m, o, _i, _arr, slot = getSlot(o.created_on.slice(11, 13))) => (
m.has(slot) ? m.get(slot).push(o) : m.set(slot, [o]), m
),
new Map()
))]
);
console.log(Object.fromEntries(grpSlot));
This is what I tried using momentjs
and lodash
.
const bookings = [{
a: 1,
created_on: '2021-04-23 10:00:01',
}, {
b: 1,
created_on: '2021-04-24 09:03:01',
}, {
b: 1,
created_on: '2021-04-24 13:03:01',
}];
const groupedByDate = bookings.reduce((acc, e) => {
const eDate = moment(e.created_on).format('YYYY-MM-DD');
if (acc[eDate]) {
acc[eDate].push(e)
} else {
acc[eDate] = [e];
}
return acc;
}, { })
const allSlots = ['00:00-04:00', '04:00-08:00', '08:00-12:00', '12:00-16:00','16:00-20:00','20:00-24:00'];
const grupedByDateAndSlots = _.mapValues(groupedByDate, (ele) => {
return ele.reduce((acc, e) => {
const createdOnDate = moment(e.created_on).format('YYYY-MM-DD');
const foundSlot = allSlots.find((slot) => moment(e.created_on).isBetween(moment(`${createdOnDate} ${slot.split('-')[0]}`), moment(`${createdOnDate} ${slot.split('-')[1]}`)))
if (acc[foundSlot]) {
acc[foundSlot].push(e)
} else {
acc[foundSlot] = [e];
}
return acc;
}, { })
})
console.log(grupedByDateAndSlots)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With