Related
This question already has an answer here:
How to merge two list of objects in a new one by date
(1 answer)
Closed 8 months ago.
I'm learning Javascript and I'm stuck in a doubt with the joining of two arrays of objects through an ID, I can join the two, but the result is not what I expect.
So, I have these two object arrays:
"product": [
{
"id": "1000",
"code": "f230fh0g3",
"name": "Bamboo Watch",
"description": "Product Description",
"image": "bamboo-watch.jpg",
"price": 65,
"category": "Accessories",
"quantity": 24,
}
]
"orders": [
{
"id": "1000",
"productID": "f230fh0g3",
"date": "2020-09-13",
"amount": 65,
"quantity": 1,
},
{
"id": "1000",
"productID": "f230fh0g3",
"date": "2020-09-13",
"amount": 65,
"quantity": 1,
},
]
and I want to join both by key (id) to get one array like this one:
"product": [
{
"id": "1000",
"code": "f230fh0g3",
"name": "Bamboo Watch",
"description": "Product Description",
"image": "bamboo-watch.jpg",
"price": 65,
"category": "Accessories",
"quantity": 24,
"orders": [
{
"id": "1000",
"productCode": "f230fh0g3",
"date": "2020-09-13",
"amount": 65,
"quantity": 1,
"customer": "David James",
"status": "PENDING"
},
{
"id": "1001",
"productCode": "f230fh0g3",
"date": "2020-05-14",
"amount": 130,
"quantity": 2,
"customer": "Leon Rodrigues",
"status": "DELIVERED"
},
]
},
{
"id": "1001",
"..."
"orders": [
{
"id": "1001",
"..."
}
]
}]
Is it possible to map these arrays in this way?
Thanks in advance
Yes, it is possible. You can use .map() and .filter() together. Assuming you have products in product variable and orders in order variable, you can compute your combined list like this:
const result = products.map(
product => ({
...product,
orders: orders.filter(
({ productID }) => productID === product.id
)
})
);
I need to calculate a score based on departments in groups. To simplify that I used only 1 group as an example.
I'm receiving this data structure:
const data = [{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 80,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "Executive",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "OOO Boost",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 60,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 100,
"count": 2,
"department": "Supporting Department",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Designers",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Executive",
"group": "Group one"
}
];
and I need to create a data structure for a heatmap:
const heatmapData = [
{
row: 'Group one',
columns: [
{
name: 'Engineering',
averageScore: 70, // (80[score] * 1[count] + 60[score] * 1[count]) / 2[sum of count -> 1+1]
},
{
name: 'Supporting Department',
averageScore: 100, // 100[score] * 2[count] / 2[sum of count -> 2]
},
.... next unique departments
]
}
]
I'm a bit stacked with some simple solution of grouping data with calculation. Could you help me please? Thank you
You can group your data based on the group and for each group, group it on department and sum up score and count. Once you have this object, you can calculate average for each department.
const data = [{ "id": "cklt7ln1k0922o0sabjkk74m9", "score": 80, "count": 1, "department": "Engineering", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 40, "count": 1, "department": "Executive", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 40, "count": 1, "department": "OOO Boost", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 60, "count": 1, "department": "Engineering", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 100, "count": 2, "department": "Supporting Department", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 20, "count": 1, "department": "Designers", "group": "Group one" }, { "id": "cklt7ln1k0922o0sabjkk74m9", "score": 20, "count": 1, "department": "Executive", "group": "Group one" } ],
grouped = data.reduce((r, {group, department, score, count}) => {
r[group] = r[group] || {};
r[group][department] = r[group][department] || {department, totalScore: 0, count: 0 };
r[group][department].totalScore += score * count;
r[group][department].count += count;
return r;
},{}),
result = Object.keys(grouped).map(k => {
const columns = Object.values(grouped[k]).map(d => ({
department: d.department,
averageScore: d.totalScore/d.count
}));
return {row: k, columns };
})
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can group items into the dictionary:
let group = data.reduce((acc, val) => {
if(!acc[val.group]) acc[val.group] = {};
if(!acc[val.group][val.department]) acc[val.group][val.department] = {sum:0, count: 0, averageScore: 0};
acc[val.group][val.department] = {
sum: acc[val.group][val.department].sum+val.score,
count: acc[val.group][val.department].count + 1,
averageScore: (acc[val.group][val.department].sum+val.score) / (acc[val.group][val.department].count + 1)
}
return acc
}, {});
then map it to requested format:
Object.keys(group).map(row => {
return {
row: row,
columns: Object.keys(group[row]).map(col => {return {name: col, averageScore: group[row][col].averageScore}})
}
})
Allow me to explain how it works.. so we know that objects are pointers more than they are values.. I used that principle throughout the solution. I have the array to return(where I push stuff), then I had 2 Objects to store values(and editing those Objects edited the "values" in the array), so in the array you pass in, I basically add values to these objects and link them in the array(the format you desire)
UPDATED AGAIN.. I applied the logic of your calculation examples >:D
function group(array){
let arr=[]; let groups={}; let departments={}
array.forEach(a=>{
if(!groups[a.group]){ //setting each group
groups[a.group]={row:a.group,columns:[]}
arr.push(groups[a.group])
}
if(!departments[a.department]){ //setting each department
departments[a.department]=[{name:a.department,averageScore:a.score*a.count},a.count] //score * count and count(because of your calculation examples)
groups[a.group].columns.push(departments[a.department][0])
}
else{ //adding department when they already exist
departments[a.department][1]+=a.count //count
departments[a.department][0].averageScore+=a.score*a.count //score * count
//(because of your calculation examples)
}
})
Object.keys(departments).forEach(a=>departments[a][0].averageScore/=departments[a][1])
return arr
}
console.log(group(data))
<script>
//to not take out unnecesary space in the answer
window.data = [{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 80,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "Executive",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 40,
"count": 1,
"department": "OOO Boost",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 60,
"count": 1,
"department": "Engineering",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 100,
"count": 2,
"department": "Supporting Department",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Designers",
"group": "Group one"
},
{
"id": "cklt7ln1k0922o0sabjkk74m9",
"score": 20,
"count": 1,
"department": "Executive",
"group": "Group one"
}
];
</script>
I am trying to get specific object from a whole object below is the example
by using localStorage.getItem('shop/elasticCache/shirt');
I get below data
{"description":"Tech Shirt","configurable_options":[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],"label":"Color","attribute_code":"color"},{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"},{"value_index":"2901","label":"Medium"},{"value_index":"2904","label":"Large"}],"label":"Size","attribute_code":"size"}],"tsk":1594790209,"size_options":[2898,2901,2904],"regular_price":28,"final_price":null,"price":28,"color_options":[5176],"special_from_date":null,"id":250659,"category":[{"category_id":2,"name":"Default Category","position":1},{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}],"sku":"S155551","product_links":[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}
I am trying to get
{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}]
Is their any way it can be done ?
const {category} = JSON.parse(localStorage.getItem('shop/elasticCache/shirt');)
or
const {category } = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
}
objc={"description":"Tech Shirt","configurable_options":
[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],
"label":"Color","attribute_code":"color"},
{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"}
,{"value_index":"2901","label":"Medium"},
{"value_index":"2904","label":"Large"}],
"label":"Size","attribute_code":"size"}],
"tsk":1594790209,"size_options":[2898,2901,2904]
,"regular_price":28,"final_price":null,"price":28,
"color_options":[5176],"special_from_date":null,"id":250659,
"category":[{"category_id":2,"name":"Default Category","position":1},
{"category_id":3,"name":"Clothing","position":14985},
{"category_id":30,"name":"Bottoms","position":798},
{"category_id":58,"name":"Leggings","position":1},
{"category_id":1130,"name":"Char Test Category","position":30}],
"sku":"S155551","product_links":
[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},
{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}]
}
res = objc["category"]
res.shift()
console.log(res)
$(document).ready(function () {
var jsonObj = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
};
for(var i = 1; i < jsonObj.category.length; i++){
console.log(jsonObj.category[i]);
}
});
You can iterate through the entire object and can get the required values. The above code gives the values of category from index 1.
I have a json file which contains the list of products.
[{"id":76,
"name":"A",
"description":"abc",
"price":199,
"imageUrl":"image.jpg",
"productCategory":[{
"categoryId":5,
"category":null
},{
"categoryId":6,
"category":null
}
]}
I then have a second json file with a list of categories which look like so:
[{"id":5,"name":"red"},
{"id":6,"name”:"blue"}]
What is the best way to join the categories of this two json files in Angular?
This is what I aim to achieve:
[{"id":76,
"name":"A",
"description":"abc",
"price":199,
"imageUrl":"image.jpg",
"productCategory":[{
"categoryId":5,
"category":red
},{
"categoryId":6,
"category":blue
}
]}
You can use filter function for your requirement as below
let products = [{
"id": 76,
"name": "A",
"description": "abc",
"price": 199,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 2,
"category": null
}, {
"categoryId": 1,
"category": null
}]
}, {
"id": 77,
"name": "B",
"description": "abcd",
"price": 1997,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 5,
"category": null
}, {
"categoryId": 6,
"category": null
}]
},
{
"id": 78,
"name": "C",
"description": "abcde",
"price": 1993,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 4,
"category": null
}, {
"categoryId": 6,
"category": null
}]
}];
let category = [{ "id": 5, "name": "red" }, { "id": 6, "name": "blue" }]
let result = products.filter(p => {
var exist = p.productCategory.filter(pc => category.find(c => c.id == pc.categoryId))[0];
return exist;
});
console.log(result);
let products = [{
"id": 76,
"name": "A",
"description": "abc",
"price": 199,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 2,
"category": null
}, {
"categoryId": 1,
"category": null
}]
}, {
"id": 77,
"name": "B",
"description": "abcd",
"price": 1997,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 5,
"category": null
}, {
"categoryId": 6,
"category": null
}]
},
{
"id": 78,
"name": "C",
"description": "abcde",
"price": 1993,
"imageUrl": "image.jpg",
"productCategory": [{
"categoryId": 4,
"category": null
}, {
"categoryId": 6,
"category": null
}]
}];
let category = [{ "id": 5, "name": "red" }, { "id": 6, "name": "blue" }]
let result = products.filter(p => {
var exist = p.productCategory.filter(pc => category.find(c => c.id == pc.categoryId))[0];
return exist;
});
console.log(result);
I make a stackblitz that use a service to retreive the data. Yes, the way is using switchMap and map. SwitchMap receive an array and must return an observable. with map, we transform the data received and return the data transformed
this.dataService.getCategories().pipe(
//first get the categories, the categories is in the
//variable cats
switchMap((cats:any[])=>{
return this.dataService.getProducts().pipe(map((res:any[])=>{
res.forEach(p=>{ //with each product
p.productCategory.forEach(c=>{ //with each productCategory in product
//equals a propertie "category" to the propertie "name" of the cats
c.category=cats.find(x=>x.id==c.categoryId).name
})
})
return res
}))
})).subscribe(res=>{
console.log(res)
})
If only has an unique product we can make
this.dataService.getCategories().pipe(
switchMap((cats:any[])=>{
return this.dataService.getUniqProduct(2).pipe(map((res:any)=>{
res.productCategory.forEach(c=>{
c.category=cats.find(x=>x.id==c.categoryId).name
})
return res
}))
})).subscribe(res=>{
console.log(res)
})
We can improve our dataService "cached" the categories
getCategories() {
if (this.categories)
return of(this.categories);
return http.get(......).pipe(tap(res=>{
this.categories=res;
}))
}
NOTE:In the stackbit I simulate the call to an http.get(...) using "of"
Suppose I have the following json file and I would like to return the 'existing.primaryBundle.products' array preferrably with lodash:
{
"existing": {
"hasPlatinum": false,
"primaryBundle": {
"id": "2008",
"name": "TV - Entertainment, Sport",
"products": [
{
"name": "Entertainment",
"id": "100",
"price": 2600,
"gifted": false
},
{
"name": "Sport",
"id": "107",
"price": 2500,
"gifted": false,
"swappableProducts": [
{
"name": "Movies",
"id": "105",
"price": 2000,
"gifted": false
}
]
}
]
},
"extrasBundle": {
"id": "131",
"name": "Optional Extras - MUTV (Sports), LFCTV (Sports), Chelsea TV (Sports)",
"products": [
{
"name": "MUTV (Sports)",
"id": "665",
"price": 0,
"gifted": false
},
{
"name": "LFCTV (Sports)",
"id": "666",
"price": 0,
"gifted": false
},
{
"name": "Chelsea TV (Sports)",
"id": "667",
"price": 0,
"gifted": false
}
]
}
}
}
I have tried lodash and use this statement:
list2 = _.pick(existing,'primaryBundle.products')
But this returns an error and not the wanted result. How can I select this products array?
you could use _.get(nameOfObject, 'existing.primaryBundle.products') of course you would need to name your object like I've done below with sampleObject;
check out the lodash docs too
const sampleObject = {
"existing": {
"hasPlatinum": false,
"primaryBundle": {
"id": "2008",
"name": "TV - Entertainment, Sport",
"products": [{
"name": "Entertainment",
"id": "100",
"price": 2600,
"gifted": false
}, {
"name": "Sport",
"id": "107",
"price": 2500,
"gifted": false,
"swappableProducts": [{
"name": "Movies",
"id": "105",
"price": 2000,
"gifted": false
}]
}]
},
"extrasBundle": {
"id": "131",
"name": "Optional Extras - MUTV (Sports), LFCTV (Sports), Chelsea TV (Sports)",
"products": [{
"name": "MUTV (Sports)",
"id": "665",
"price": 0,
"gifted": false
}, {
"name": "LFCTV (Sports)",
"id": "666",
"price": 0,
"gifted": false
}, {
"name": "Chelsea TV (Sports)",
"id": "667",
"price": 0,
"gifted": false
}]
}
}
}
console.log(_.get(sampleObject, 'existing.primaryBundle.products'));
The main reason why it returns an error is because existing is not a global scoped object, you have to assign object to some variable like const obj = {...} and then pass the parameter to _pick method as obj.existing, yet I don't see a reason to use lodash in here, you can just reference the path to that object directly.