Javascript: create a deeply nested object in javascript from another object - javascript

Javascript: How to dynamically create a deeply nested object from an array of objects?
I could achieve one level of separation, but the code has got quite complicated and am not able to figure out how to achieve this for 2nd level.
Actual:
[{
brandId: 1,
spec_desc: "engines",
av: 3000
tv: 1000,
brandName: "bmw",
id: 1,
group: "cars",
cost: 20000.00,
currency: "USD",
desc: "manufacturing costs"
},
{
brandId: 1,
spec_desc: "brakes",
av: 1000,
tv: 2000,
brandName: "bmw",
id: 1,
....
},
{
brandId: 2,
spec_desc: "engines",
av: 1800,
tv: 2500,
brandName: "audi",
id: 2
....
}
]
Expected:
[{
group: "cars",
id: 1,
brands: [{
brandId: 1,
brandName: "BMW",
specs: {
power: [{
spec_desc: "engines",
av: 3000,
tv: 1000
},
{
spec_desc: "brakes",
av: 1000,
tv: 2000
}
],
cost: {
desc: "manufacturing costs",
value: 20000.00,
currency: "USD"
}
}
},
{
brandId: 2,
brandName: "audi",
specs: {
power: [
...
],
}
}
]
},
group: "bikes",
id: 2,
brands: [
....
]
]
Here is what I have tried, but able to obtain grouping only till brandName i-e one level.
function genrows(groups, groupKey) {
return _.toPairs(groups).map(([key, units]) => ({
[groupKey]: key,
units
}))
}
function gengroups(arr, iteratee, key) {
const grouped = _.groupBy(arr, iteratee)
return genrows(grouped, key)
}
function grouparray(units, props) {
let result = [{
units
}]
props.forEach((prop, i) => {
const key = prop
const iteratee = prop.iteratee || prop
result = _.flatten(
result.map(row => {
return gengroups(row.units, iteratee, key).map(group =>
// {...row, ...{ [key]: group[key], units: group.units }}
({ ...row,
[key]: group[key],
units: group.units
}),
)
}),
)
})
return _.flatten(result)
}
const groups = ['brandName', 'id'] //group by key names
// it fetches out these group tags to generate keys,
const desired = grouparray(actual, groups);
Can anyone help me work out how to achieve this dynamically? If you've got this far thanks very much for taking the time to read even if you can't help.
PS: Let me know for further clarifications, my result object & also have used lodash functions.

You could take a classic approach by storing the last group, where an id is found and group the brands with this object.
var data = [{ brandId: 1, spec_desc: "engines", av: 3000, tv: 1000, brandName: "bmw", id: 1, group: "cars", cost: 20000.00, currency: "USD", desc: "manufacturing costs" }, { brandId: 1, spec_desc: "brakes", av: 1000, tv: 2000, brandName: "bmw" }, { brandId: 2, spec_desc: "engines", av: 1800, tv: 2500, brandName: "audi" }],
lastGroup,
result = data.reduce((r, { brandId, spec_desc, av, tv, brandName, id, group, cost: value, currency, desc }) => {
if (id !== undefined) r.push(lastGroup = { group, id, brands: [] });
var brand = lastGroup.brands.find(q => q.brandId === brandId);
if (!brand) lastGroup.brands.push(brand = { brandId, brandName, specs: { power: [], cost: { desc, value, currency } } });
brand.specs.power.push({ spec_desc, av, tv });
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Set the boolean property inside all objects with matched name

I have a nested object that looks like this
const test = {
cat1: {
id: "c1",
name: "category1",
items: [
{
itemName: "item1",
points: 1,
used: true
},
{
itemName: "item2",
points: 3,
used: false
},
{
itemName: "item3",
points: 5,
used: true
}
]
},
cat2: {
id: "c2",
name: "category2",
items: [
{
itemName: "item4",
points: 7,
used: true
},
{
itemName: "item5",
points: 9,
used: false
}
]
},
cat3: {
id: "c3",
name: "category3",
items: [
{
itemName: "item6"
}
]
}
};
These items are then drawn as checkbox with used property as its checked value. So whenever I click on Select All all the items having used property inside the objects should be set to true. When Unselect All, all the items used property should be set to false. I prefer having just one function that basically takes type as Select All or Unselect All as key and a category name so that items under that name will be set to either true or false
Here is my try
function handleOperation(id, type){
const output = Object.fromEntries(
Object.entries(test)
.map(([k, { items, ...rest }]) => [
k,
{
...rest,
items : type === 'Select All' ?
items[k] = items[k].map(item => {
item.used = true;
return item;
}) :
items[k] = items[k].map(item => {
item.used = false;
return item;
})
}
]);
);
return output;
}
console.log(handleOperation('category1', 'Select All'));
console.log(handleOperation('category2', 'Unselect All'));
So when I pass handleOperation('category1', 'Select All')
It should give me, since category1 items should be updated to true
const test = {
cat1: {
id: "c1",
name: "category1",
items: [
{
itemName: "item1",
points: 1,
used: true
},
{
itemName: "item2",
points: 3,
used: true
},
{
itemName: "item3",
points: 5,
used: true
}
]
},
cat2: {
id: "c2",
name: "category2",
items: [
{
itemName: "item4",
points: 7,
used: true
},
{
itemName: "item5",
points: 9,
used: false
}
]
},
cat3: {
id: "c3",
name: "category3",
items: [
{
itemName: "item6"
}
]
}
}
Since you want to clone the objects (although you could avoid cloning the ones that don't change; probably an unnecessary optimization), you're on the right track with Object.fromEntries, Object.entries, and map. But you seem to be using the wrong property names, and the code doesn't have to be as complicated as shown.
function handleOperation(type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, { items, ...rest }]) => [
key,
{
// Copy the rest of this object
...rest,
// Copy its array while mapping the objects
items: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
])
);
}
const test = {
cat1: {
id: "c1",
name: "category1",
items: [
{
itemName: "item1",
points: 1,
used: true,
},
{
itemName: "item2",
points: 3,
used: false,
},
{
itemName: "item3",
points: 5,
used: true,
},
],
},
cat2: {
id: "c2",
name: "category2",
items: [
{
itemName: "item4",
points: 7,
used: true,
},
{
itemName: "item5",
points: 9,
used: false,
},
],
},
cat3: {
id: "c3",
name: "category3",
items: [
{
itemName: "item6",
},
],
},
};
function handleOperation(type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, { items, ...rest }]) => [
key,
{
// Copy the rest of this object
...rest,
// Copy its array while mapping the objects
items: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
])
);
}
console.log("Select All:");
console.log(handleOperation("Select All"));
console.log("Unselect All:");
console.log(handleOperation("Unselect All"));
.as-console-wrapper {
max-height: 100% !important;
}
In a comment you've asked:
Thanks a ton. If I want to modify items array with category name being passed. What could be modified? Something like calling handleOperation('category1', 'Select All')), So that only category1 items objects are set to true
One way we could do that is to just avoid calling map on items if the name of the category doesn't match, using the existing items array:
function handleOperation(categoryName, type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, { name, items, ...rest }]) => [
key,
{
// Copy the name
name,
// Copy the rest of this object
...rest,
// If the name doesn't match, reuse `items`; if it does match,
// copy its array while mapping the objects
items:
name !== categoryName
? items
: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
])
);
}
const test = {
cat1: {
id: "c1",
name: "category1",
items: [
{
itemName: "item1",
points: 1,
used: true,
},
{
itemName: "item2",
points: 3,
used: false,
},
{
itemName: "item3",
points: 5,
used: true,
},
],
},
cat2: {
id: "c2",
name: "category2",
items: [
{
itemName: "item4",
points: 7,
used: true,
},
{
itemName: "item5",
points: 9,
used: false,
},
],
},
cat3: {
id: "c3",
name: "category3",
items: [
{
itemName: "item6",
},
],
},
};
function handleOperation(categoryName, type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, { name, items, ...rest }]) => [
key,
{
// Copy the name
name,
// Copy the rest of this object
...rest,
// If the name doesn't match, reuse `items`; if it does match,
// copy its array while mapping the objects
items:
name !== categoryName
? items
: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
])
);
}
console.log("category1 - Select All:");
console.log(handleOperation("category1", "Select All"));
console.log("category1 - Unselect All:");
console.log(handleOperation("category1", "Unselect All"));
.as-console-wrapper {
max-height: 100% !important;
}
But that unnecessarily copies category objects. So let's avoid that as well:
function handleOperation(categoryName, type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, category]) => {
if (category.name !== categoryName) {
return [key, category];
}
const { name, items, ...rest } = category;
return [
key,
{
// Copy the name
name,
// Copy the rest of this object
...rest,
// Copy its array while mapping the objects
items: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
];
})
);
}
const test = {
cat1: {
id: "c1",
name: "category1",
items: [
{
itemName: "item1",
points: 1,
used: true,
},
{
itemName: "item2",
points: 3,
used: false,
},
{
itemName: "item3",
points: 5,
used: true,
},
],
},
cat2: {
id: "c2",
name: "category2",
items: [
{
itemName: "item4",
points: 7,
used: true,
},
{
itemName: "item5",
points: 9,
used: false,
},
],
},
cat3: {
id: "c3",
name: "category3",
items: [
{
itemName: "item6",
},
],
},
};
function handleOperation(categoryName, type) {
// Get a flag for `type`
const used = type === "Select All";
// Build the updated objects
return Object.fromEntries(
Object.entries(test).map(([key, category]) => {
if (category.name !== categoryName) {
return [key, category];
}
const { name, items, ...rest } = category;
return [
key,
{
// Copy the name
name,
// Copy the rest of this object
...rest,
// Copy its array while mapping the objects
items: items.map((item) => ({
// Copy `items`'s properties
...item,
// Set the flag from our `used `variable
used,
})),
},
];
})
);
}
console.log("category1 - Select All:");
console.log(handleOperation("category1", "Select All"));
console.log("category1 - Unselect All:");
console.log(handleOperation("category1", "Unselect All"));
.as-console-wrapper {
max-height: 100% !important;
}

Merge item in array of object with the same ID on Javascript

this is how the object look:
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 1',
price: '200',
},
},
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 2',
price: '230',
},
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 1',
price: '305',
},
}
];
i want the item object will merge if the object have the same brandID :
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: [
{
name: 'Adidas 1',
price: '200',
},
{
name: 'Adidas 2',
price: '230',
},
],
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 2',
price: '316',
},
},
];
is there any javascript syntax or method to do this ? and with an explanation will be very nice, Thank You
(Assuming that your output is just a typo and name/price doesn't actually changes) You can use array reduce
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 1',
price: '200',
},
},
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 2',
price: '230',
},
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 1',
price: '305',
},
}
];
const mergedItems = data.reduce((acc, curr) => {
// check if current exist on the accumulator
const exist = acc.find(brand => brand.brandId === curr.brandId);
// if it does, add the item on it
if (exist) {
return acc.map((brand) => {
if (brand.brandId === exist.brandId) {
return {
...brand,
item: brand.item.concat(curr.item),
}
}
})
}
// if it doesnt, add it on accumulator, and make the item array
return acc.concat({
...curr,
item: [
curr.item
]
})
})
(I wrote the code manually and not tested)
You can simply achieve this result using Map
let data = [
{
brandId: "12345",
brand: "Adidas",
item: {
name: "Adidas 1",
price: "200",
},
},
{
brandId: "12345",
brand: "Adidas",
item: {
name: "Adidas 2",
price: "230",
},
},
{
brandId: "7878",
brand: "Nike",
item: {
name: "Nike 1",
price: "305",
},
},
];
const dict = new Map();
data.forEach((o) => {
dict.get(o.brandId)
? dict.get(o.brandId).item.push(o.item)
: dict.set(o.brandId, { ...o, item: [o.item] });
});
const result = [];
for (let [k, v] of dict) {
v.item.length === 1 ? result.push({ ...v, item: v.item[0] }) : result.push(v);
}
console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

Conditional copying properties and values from one array of objects to another

Got two arrays of objects and my goal is to check if the value under property id from array1 matches the value under the property categoryId of array2. When find a match want to add the missing property amount to the relevant member of array1 or create a new array containing all the properties and values I need - id, name, amount
Here are the two arrays:
const array1 = [{
id: 8,
name: 'Online Shopping',
},
{
id: 12,
name: 'Subscriptions',
},
{
id: 5,
name: 'Patreon donations',
}]
and
const array2 = [
{
expence: {
amount: -66.66,
},
categoryId: 5,
},
{
expence: {
amount: 100018.85,
},
categoryId: 0,
},
{
expence: {
amount: -43340.9,
},
categoryId: 12,
},]
Tried to combine different approaches from answers to similar but simpler cases already posted in the community but didn't managed to make them work in my case.
Loop through each item in array1, then loop through each item in array2 inside the loop and check whether the categoryId is equal to the id.
const array1 = [{
id: 8,
name: 'Online Shopping',
},
{
id: 12,
name: 'Subscriptions',
},
{
id: 5,
name: 'Patreon donations',
}
]
const array2 = [{
expence: {
amount: -66.66,
},
categoryId: 5,
},
{
expence: {
amount: 100018.85,
},
categoryId: 0,
},
{
expence: {
amount: -43340.9,
},
categoryId: 12,
},
]
array1.forEach((e) => {
array2.forEach((f) => {
if (f.categoryId == e.id) {
e.amount = f.expence.amount;
}
})
})
console.log(array1);
You can also make use of Array.filter to find the item where the categoryId is equal to the id:
const array1 = [{
id: 8,
name: 'Online Shopping',
},
{
id: 12,
name: 'Subscriptions',
},
{
id: 5,
name: 'Patreon donations',
}
]
const array2 = [{
expence: {
amount: -66.66,
},
categoryId: 5,
},
{
expence: {
amount: 100018.85,
},
categoryId: 0,
},
{
expence: {
amount: -43340.9,
},
categoryId: 12,
},
]
array1.forEach((e) => {
var arr = array2.filter(f => f.categoryId == e.id);
if(arr.length > 0) e.amount = arr[0].expence.amount;
})
console.log(array1);

How do I get the total sum of nested arrays in Reactjs?

I want to get the total price of nested arrays in a specific category e.g: Hot Drinks.
Here is a sample of what I have now, so I want to filter out and get the total price of Hot Drinks Category only.
[
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]
You can apply a filter method on the array and then just add the values on the filtered array. Something like below:
let prod = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
];
function getPriceByCategory(category, products) {
let price = 0;
products.forEach(orders => {
orders.orderItems.filter(order => order.category == category).forEach(item => {
price += item.price;
});
});
return price;
}
const totalPrice = getPriceByCategory('Hot Drinks', prod);
alert(totalPrice);
Sample JS Fiddle: https://jsfiddle.net/sagarag05/qwzju53f/9/
const filterBy = 'Hot Drinks';
const items = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]
const sumOf = (items, filterBy) => {
let totalPrice = 0;
items.forEach(item => {
item.orderItems.forEach(orderItem => {
if (orderItem.category === filterBy) {
totalPrice += orderItem.price;
}
})
})
return totalPrice;
}
console.log(sumOf(items, filterBy))
let sum = 0;
allOrders.forEach(order => {
order.orderItems.forEach(item => {
if(item.category=='Hot Drinks') {
sum+ = item.price * item.qty
}});
});
sum has the total price for Hot Drinks
Assuming you named that information as data:
Generate a big array of all the "orderItems"
For each of those elements sum the price if the category is "Hot Drinks"
const totalPrice = data
.reduce((acc, { orderItems }) => [...acc, ...orderItems], [])
.reduce((acc, { category, price }) => category === "Hot Drinks" ? acc + price : acc, 0);
console.log(totalPrice); // 10
Use flatMap and reduce or alternatively using forEach and destructuring
const total = (arr, text) =>
arr
.flatMap(({ orderItems }) => orderItems)
.reduce((acc, { category, price }) =>
(acc + (category === text ? price : 0)), 0);
// alternatively
const total2 = (arr, text, acc = 0) => {
arr.forEach(({ orderItems }) =>
orderItems.forEach(
({ category, price }) => (category === text && (acc += price))
)
);
return acc;
};
const data = [
{
totalPrice: 30,
_id: "6014fa4324e125599eaa72b5",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Breakfast",
name: "food name 1",
price: 3,
qty: 1,
},
{
_id: "6014fa4324e125599eaa747s5",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 5,
},
{
_id: "6014fa4324e125599eaa74767",
category: "Hot Drinks",
name: "drink name 2",
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: "6014fa4324e125599eaa7276e",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 6,
},
],
},
];
console.log(total(data, 'Hot Drinks'))
console.log(total2(data, 'Hot Drinks'))

What's the most efficent way to populate an a property of an array of objects with a larger array with data?

I have a small array of objects with properties, like so:
[
{
topicName: 'Clicks',
topic: 1,
dates: [ <PLACE VALUES HERE> ],
},
{
topicName: 'Cost',
topic: 2,
dates: [ <PLACE VALUES HERE> ],
},
];
Then I have a large array of objects that I wish to extract some of the properties from in to the above dates array.
Here's what the data I wish to extract from:
[
{
"date": "2014-02-01",
"device": "Computer",
"match-type": "NA",
"clicks": 66,
"revenue": 1037,
"conversions": 2,
"cost": 284.35,
"impressions": 5330,
"ROI": 3.64691401441885
},
{
"date": "2014-02-01",
"device": "Tablet",
"match-type": "NA",
"clicks": 38,
"revenue": 587,
"conversions": 2,
"cost": 194.01000000000005,
"impressions": 1934,
"ROI": 3.025617236224936
},
{
"date": "2014-02-02",
"device": "Tablet",
"match-type": "NA",
"clicks": 40,
"revenue": 587,
"conversions": 2,
"cost": 190,
"impressions": 1934,
"ROI": 3.025617236224936
},
]
Now I need the data from all of the members of the last array and insert that releveant data for the particular object in the first array (totalling where necessary), like so:
[
{
topicName: 'Clicks',
topic: 1,
dates: [
{
date: '2014-02-01',
value: 104
},
{
date: '2014-02-02',
value: 40
}
],
},
{
topicName: 'Cost',
topic: 2,
dates: [
{
date: '2014-02-01',
value: 284,3519401
},
{
date: '2014-02-02',
value: 190
}
],
},
];
The target is the latest version of Chrome and I'm using Webpack with Babel so all the latest stuff is available.
Assuming the last dataset can be pretty large, what's the most efficient way to go about this?
[EDIT]
This is what I've come up with so far:
const dataAdapter = rawData => {
const topics = ['clicks', 'revenue', 'cost', 'roi'];
const topicsData = topics.map((topic, index) => {
const thisTopic = {};
thisTopic.topicName = topic;
thisTopic.topic = index;
thisTopic.dates = [];
return thisTopic;
});
const convertedData = topicsData.map(topicData => {
const thisTopic = topicData;
const map = new Map();
rawData.forEach(elem => {
map.set(elem.date, (map.get(elem.date) || 0) + elem[[thisTopic.topicName]]);
});
thisTopic.dates = Array.from(map);
return thisTopic;
});
return convertedData;
};
Thanks,
/J
You could take an object as reference to the wanted keys and date. Then iterate data and check if a reference to a result set exists. If not, create a new result set.
var result = [{ topicName: 'Clicks', topic: 1, dates: [], }, { topicName: 'Cost', topic: 2, dates: [], }],
data = [{ date: "2014-02-01", device: "Computer", "match-type": "NA", clicks: 66, revenue: 1037, conversions: 2, cost: 284.35, impressions: 5330, ROI: 3.64691401441885 }, { date: "2014-02-01", device: "Tablet", "match-type": "NA", clicks: 38, revenue: 587, conversions: 2, cost: 194.01000000000005, impressions: 1934, ROI: 3.025617236224936 }, { date: "2014-02-02", device: "Tablet", "match-type": "NA", clicks: 40, revenue: 587, conversions: 2, cost: 190, impressions: 1934, ROI: 3.025617236224936 }],
hash = { clicks: { _: result[0].dates }, cost: { _: result[1].dates }, };
data.forEach(function (o) {
['clicks', 'cost'].forEach(function (k) {
if (!hash[k][o.date]) {
hash[k][o.date] = { date: o.date, value: o[k] };
hash[k]._.push(hash[k][o.date]);
return;
}
hash[k][o.date].value += o[k];
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Assuming your data is in data variable and topics are in topics variable. This solution uses only javascript builtin objects.
const getPropDateMap = (obj, prop) => obj
.reduce((accObj, item) => {
return Object.assign(accObj, {
[item.date]: item.clicks + (accObj[item.date] || 0)
})
}, {})
topics.forEach(topic => {
topic.dates = Object
.entries(getPropDateMap(data, topic.topicName.toLowerCase()))
.map(entry => ({date: entry[0], value: entry[1]}))
})

Categories