How to map and group array of objects - javascript

I'm building an application with Node.js, Express, Postgres and Sequelize.
I get a response that looks like this:
[
{
"id": 101,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 102,
"type": 4,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
},
{
"id": 103,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 104,
"type": 0,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
}
]
I want to group all the events that happen on the same date.
I tried
_.forEach(response, function(value) {
_.groupBy(value, value.bookings[0].date)
})
but it doesn't work.
How can I map and group an array?
Eventually I want to have an object (or array) that looks something like this:
{
2019-04-15: [
{ id: 101, type: 0 }, { id: 103, type: 0}
],
2019-04-17: [
{ id: 102, type: 4 }, { id: 104, type: 0}
]
}

You can use reduce
let data = [{"id": 101,"type": 0,"bookings": [{"date": "2019-04-15T02:00:00.000Z"}]},{"id": 102,"type": 4,"bookings": [{"date": "2019-04-17T02:00:00.000Z"}]},{"id": 103,"type": 0,"bookings": [{"date": "2019-04-15T02:00:00.000Z"}]},{"id": 104,"type": 0,"bookings": [{"date": "2019-04-17T02:00:00.000Z"}]}]
let op = data.reduce((op,{bookings,...rest}) => {
let key = bookings[0].date.split('T',1)[0]
op[key] = op[key] || []
op[key].push(rest)
return op
},{})
console.log(op)

You can use the function reduce for grouping the objects by date.
This is assuming the array has only one index.
let arr = [ { "id": 101, "type": 0, "bookings": [ { "date": "2019-04-15T02:00:00.000Z" } ] }, { "id": 102, "type": 4, "bookings": [ { "date": "2019-04-17T02:00:00.000Z" } ] }, { "id": 103, "type": 0, "bookings": [ { "date": "2019-04-15T02:00:00.000Z" } ] }, { "id": 104, "type": 0, "bookings": [ { "date": "2019-04-17T02:00:00.000Z" } ] }];
let result = arr.reduce((a, {id, type, bookings: [{date}]}) => {
let key = date.substring(0, 10);
(a[key] || (a[key] = [])).push({id, type});
return a;
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can also use this to accomplish what you're looking for.
let response = [
{
"id": 101,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 102,
"type": 4,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
},
{
"id": 103,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 104,
"type": 0,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
}
]
let dateGroupings = {};
response.forEach((v)=> {
let date = v.bookings[0].date.substring(0,10)
if (!dateGroupings[date]){
dateGroupings[date] = [];
}
let obj = {
id: v.id,
type: v.type
};
dateGroupings[date].push(obj);
})

Well i didn't see that many answers but since i did it too
const data = [
{
"id": 101,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 102,
"type": 4,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
},
{
"id": 103,
"type": 0,
"bookings": [
{
"date": "2019-04-15T02:00:00.000Z"
}
]
},
{
"id": 104,
"type": 0,
"bookings": [
{
"date": "2019-04-17T02:00:00.000Z"
}
]
}
];
const bookingsByDate = {};
data.forEach((booking) => {
booking.bookings.forEach((bookingDate) => {
const date = new Date(bookingDate.date);
const day = date.getDate() < 10 ? '0' + date.getDate(): date.getDate();
const month = date.getMonth() < 10 ? '0' + date.getMonth(): date.getMonth();
const year = date.getFullYear();
const fullDate = year + '-' + month + '-' + day;
if(!bookingsByDate[fullDate]) {
bookingsByDate[fullDate] = [];
}
bookingsByDate[fullDate] = [
...bookingsByDate[fullDate],
{
id: booking.id,
type: booking.type,
}
]
});
})
console.log(bookingsByDate);

Related

How to use find objects in multiple levels of nested arrays

What I want is to find an object in a nested array, and to get it by a pre-known ScheduleId number, and where the Duration property is defined.
We need to find this element which is contained inside of array of "Columns", and "Columns" are contained within "Table" elements.
After finding this object, I want to update ScheduleId = 0 and Duration = 0.
Sample data:
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
Pseudo code:
var requestedScheduleId = 22;
var requestedObj = data.Table.find(x => requestedScheduleId.Equals(x.Columns.ScheduleId) )
requestedObj.ScheduleId = 0;
requestedScheduleId.Duration = 0;
Unsuccessful attempt:
var test = data.Table.map(({ Columns }) => {return Columns = Columns.filter(({ ScheduleId }) => ScheduleId == 22 )});
console.log(test);
I would not use .map or .filter for this. It's a plain and simple nested loop: For each table, for each column, if condition is met, do something.
Either with for loops:
for (table of data.Table) {
for (column of table.Columns) {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
}
}
or with Array#forEach:
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === 22) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
var data = {
"Headers": [
"A",
"B",
"C",
"D"
],
"Table": [
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 12,
},
],
},
{
"Columns": [
{
"Duration": 22,
"ScheduleId": 44,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 1648,
},
],
},
{
"Columns": [
{
"Duration": 0,
"ScheduleId": 22,
},
],
},
]
};
var requestedScheduleId = 22;
data.Table.forEach(table => {
table.Columns.forEach(column => {
if (column.ScheduleId === requestedScheduleId) {
column.ScheduleId = 0;
column.Duration = 0;
}
});
});
console.log(data);

Replacing values in array which are received as argument of a method

In this array children array can have more childrens. I have a method in which I will get "lowValue" and "highValue". "Id" will be unique. when my method get called I need to use this unique id and replace old values of "lowValue" and "highValue" with the new ones. How can I do that?
// put your code here
<script>
myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
</script>
Simple
const data = your_original_data
function replacer(lowValue, highValue, id){
for(let i = 0; i < data.length; i++){
for(let j = 0; j < data[i].children.length; j++){
if(data[i].children[j].data.id === id){
data[i].children[j].data.lowValue = lowValue
data[i].children[j].data.highValue = highValue
return
}
}
}
}
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
]
const indexMap = new Map()
const parseDataToMap = (data = []) => {
data.forEach(e => {
if (e.children) {
e.children.forEach(e => {
indexMap.set(e.data.id, e.data)
})
}
})
}
parseDataToMap(myData)
console.log(myData[0].children[0].data)
const o = indexMap.get(1)
o.highValue = 25
o.lowValue = 11
console.log(myData[0].children[0].data)
Given the below-mentioned assumptions:
All children where id matches the supplied value will have the lowValue and highValue replaced.
The supplied id will always be present in the myData array in one or more children.
the following is one possible solution to achieve the desired result:
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => (
arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], [])
);
Explanation / Approach
The outer .reduce helps to iterate through the myData array
Each element in this array is placed as-is (using the ... spread operator)
Next, the children prop of each myData element is specified
Within this, i.children array is iterated using map to access each element
Each element here (again) is placed as-is using the ... spread-operator
Next, data is specified
Values for the data object are also spread (as before)
Then, if the data.id matches the parameter id then, lowValue and highValue are updated (using parameters lv and hv, respectively)
The ...( some_condition ? {k: v} : {} ) is one way to update an object's specific prop/s only when some_condition is true
Please use comments below to ask for further clarification/s.
Code Snippet
const myData = [{
"data": {
"name": "Applications",
"size": "200mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 1,
"name": "editor.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
}
},
{
"data": {
"id": 2,
"name": "settings.app",
"highValue": 20,
"ratingID": 0,
"lowValue": 10,
"mappedPersonaCount": 0,
}
}
]
},
{
"data": {
"name": "Cloud",
"size": "20mb",
"type": "Folder"
},
"children": [{
"data": {
"id": 5,
"name": "backup-1.zip",
"highValue": 20,
"ratingID": 0,
"lowValue": 10
}
}]
}
];
const replaceValues = (id = 5, lv = 5, hv = 50, arr = myData) => arr.reduce((f, i) => [...f, {
...i,
children: i.children.map(
child => ({
...child,
data: {
...child.data,
...(
child.data.id === id ? {
lowValue: lv,
highValue: hv
} : {}
)
}
})
)
}], []);
console.log('replace id: 5, low: 5, high: 50', replaceValues());
console.log('replace id: 1, low: 11, high: 21', replaceValues(1, 11, 21));

how to change the format of json array by loping over

Hi I am getting data from API but I want my data in different format so that I can pass later into a function. I want to change the names of keys into a different one becasuse I have created a chart and it only draws if I send it data in certain way
This is what I am getting from API
data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [
{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [
{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
But I want my data to look like this like this
data = {
"name": "KSE100",
"children": [
{
"name": "A",
'points': -9,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [
{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
Like I want to replace
stock_sector_name = name
sector_score = value
stocks = children
stock_symbol = name
stock_score = value
I have been trying this for so much time but sill could not figured it out
function convert(d){
return {
name : d.indice,
children : d.data.map(y=>{
return {
name : y.stock_sector_name,
points : y.sector_score,
children : y.stocks.map(z=>{
return {
stock_title: z.stock_symbol,
value : z.stock_score
}
})
}
})
}
}
You can do something like this
const data = {
"status": "success",
"from": "DB",
"indice": "KSE100",
"data": [{
"stock_sector_name": "Tc",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "TRG",
"stock_score": 44
},
{
"stock_symbol": "SYS",
"stock_score": 33
}
]
},
{
"stock_sector_name": "OIL",
"sector_score": "0828",
"stocks": [{
"stock_symbol": "FFS",
"stock_score": 44
},
{
"stock_symbol": "SMS",
"stock_score": 33
}
]
},
]
}
const data2 = {
"name": "KSE100",
"children": [{
"name": "A",
'points': -9,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"stock_title": "B",
"value": 4,
},
]
},
{
"name": "B",
'points': 20,
"children": [{
"stock_title": "A",
"value": 12,
},
{
"name": "B",
"value": 4,
},
]
},
]
}
//stock_sector_name = name
//sector_score = value
//stocks = children
//stock_symbol = stock_title
//stock_score = value
const keys = {
stock_sector_name: "name",
sector_score: "points",
stocks: "children",
stock_symbol: "stock_title",
stock_score: "value",
indice: "name",
//data: "children"
}
const rename = (value) => {
if (!value || typeof value !== 'object') return value;
if (Array.isArray(value)) return value.map(rename);
return Object.fromEntries(Object
.entries(value)
.map(([k, v]) => [keys[k] || k, rename(v)])
);
}
renamedObj = rename(data);
console.log(renamedObj);

Creating array of objects based on another array of objects

Trying creating array of objects based on another array of objects. Decided to use flatmap and then reduce, but the problem is when I have more than one object in result array - I can not collected several statuses in one object. Have added what i tried and what is result I am trying to achieve.
What I have
const data = [
{
"timestamp": "2021-08-31T15:29:18Z",
"result": [
{
"label": "Not Covered",
"value": 132
}
]
},
{
"timestamp": "2021-09-30T15:29:18Z",
"result": [
{
"label": "Not Covered",
"value": 135
}
]
},
{
"timestamp": "2021-10-31T16:29:18Z",
"result": [
{
"label": "Not Covered",
"value": 135
}
]
}
]
What I need to get
[
{
"Not Covered":132,
"Active":0,
"Expiring Soon":0,
"timestamp": "2021-08-31T15:29:18Z"
},
{
"Not Covered":135,
"Active":0,
"Expiring Soon":0,
"timestamp": "2021-09-30T15:29:18Z"
},
{
"Not Covered":135,
"Active":0,
"Expiring Soon":0,
"timestamp": "2021-10-31T16:29:18Z"
}
]
What I am doing
let flattenedResult = data.flatMap(({result,...r}) => result.map(o => ({ ...o,...r})));
const chartData = flattenedResult.reduce((acc, item) => {
const {timestamp, value,label} = item;
acc.push({timestamp, "Not Covered":"Not Covered"===label?value:0,"Active":"Active"===label?value:0,"Expiring Soon":"Expiring Soon"===label?value:0});
return acc;
}, []);
What i am getting:
[
{
"timestamp": "2021-08-31T15:29:18Z",
"Not Covered": 132,
"Active": 0,
"Expiring Soon": 0
},
{
"timestamp": "2021-09-30T15:29:18Z",
"Not Covered": 135,
"Active": 0,
"Expiring Soon": 0
},
{
"timestamp": "2021-10-31T16:29:18Z",
"Not Covered": 135,
"Active": 0,
"Expiring Soon": 0
}
]
You haven't explained how to get the values "Active" and "Expiring soon", but I'm sure something like that should help
const data = [
{
"timestamp": "2021-08-31T15:29:18Z",
"result": [
{
"label": "Expiring Soon",
"value": 57
},
{
"label": "Not Covered",
"value": 132
},
{
"label": "Active",
"value": 42
}
]
},
{
"timestamp": "2021-09-30T15:29:18Z",
"result": [
{
"label": "Not Covered",
"value": 135
}
]
},
{
"timestamp": "2021-10-31T16:29:18Z",
"result": [
{
"label": "Not Covered",
"value": 135
},
{
"label": "Active",
"value": 42
}
]
}
];
console.log(data.reduce((acc, {timestamp, result}) => {
const datum = result.reduce((acc, {label, value}) => {
acc[label] = value;
return acc;
}, {
timestamp,
'Not Covered': 0,
Active: 0,
'Expiring Soon': 0
});
return acc.concat(datum);
}, []));
What about something like this? You can then just put your "Active" and "ExpringSoon" according to your business logic.
const array = data.map(item => {
const results = {}
item.result.forEach(({ label, value }) => results[label] = value )
return {
Active: 0,
ExpiringSoon: 0,
timestamp: item.timestamp,
...results
}
})
Result
[
{
Active: 0,
ExpiringSoon: 0,
timestamp: '2021-08-31T15:29:18Z',
'Not Covered': 132
},
{
Active: 0,
ExpiringSoon: 0,
timestamp: '2021-09-30T15:29:18Z',
'Not Covered': 135
},
{
Active: 0,
ExpiringSoon: 0,
timestamp: '2021-10-31T16:29:18Z',
'Not Covered': 135
}
]

How to replace key/value pairs in an object of two arrays of objects

I would like to replace the key 'id' and it's value with the property of 'type' with a value of 'inc'or 'exp'. I also want to delete the property 'percentage' from the objects in the exp array.
In the end I want to merge al the objects into one array.
This is what I did, it has the desired outcome but there must be a shortcut to achieve this, with less code and cleaner. Thanks!
const list = {
exp: [
{ id: 0, value: 57, percentage: 12 },
{ id: 1, value: 34, percentage: 10 },
],
inc: [
{ id: 1, value: 18 },
{ id: 1, value: 89 },
],
};
// Deep copy of list object
let newList = JSON.parse(JSON.stringify(list));
// Destructuring
const { exp, inc } = newList;
for (let obj of exp) {
obj.type = "exp";
delete obj.id;
delete obj.percentage;
}
for (let obj2 of inc) {
obj2.type = "inc";
delete obj2.id;
}
//Spread operator
newList = [...newList.exp, ...newList.inc];
console.log(newList);
You could use flatMap in the support of Object.entries()
const list = {
exp: [
{ id: 0, value: 57, percentage: 12 },
{ id: 1, value: 34, percentage: 10 },
],
inc: [
{ id: 1, value: 18 },
{ id: 1, value: 89 },
],
};
const res = Object.entries(list).flatMap(([type, values]) =>
values.map((value) => ({
value: value.value,
type: type,
}))
);
console.log(res);
Step by step
A = Object.entries(list)
// -->
[
[
"exp",
[
{ "id": 0, "value": 57, "percentage": 12 },
{ "id": 1, "value": 34, "percentage": 10 }
]
],
[
"inc",
[
{ "id": 1, "value": 18 },
{ "id": 1, "value": 89 }
]
]
]
B = A.map(...)
// -->
[
[
{ "value": 57, "type": "exp" },
{ "value": 34, "type": "exp" }
],
[
{ "value": 18, "type": "inc" },
{ "value": 89, "type": "inc" }
]
]
C = B.flat()
// -->
[
{ "value": 57, "type": "exp" },
{ "value": 34, "type": "exp" },
{ "value": 18, "type": "inc" },
{ "value": 89, "type": "inc" }
]
flatMap is the combination of step B and C (.map then .flat)
If value is the only property you want:
const list = {
exp: [
{ id: 0, value: 57, percentage: 12 },
{ id: 1, value: 34, percentage: 10 }
],
inc: [
{ id: 1, value: 18 },
{ id: 1, value: 89 }
]
};
const newList = [];
const types = Object.keys(list);
types.forEach((type) => {
list[type].forEach(({ value }) => {
newList.push({ type, value });
});
});
console.log(newList);
console.log(JSON.stringify(newList));

Categories