I am getting data from API structured like this:
interface ProductModel {
prod_id: string,
brand: string,
...
}
interface OrderModel {
order_id: string,
prod_id: string,
...
}
const data = {
products: ProductModel[],
orders: OrderModel[]
}
What I want is to restructure the data to group the orders of a product and the product info in one object:
const expectedStructure = {
prod_id: string,
brand: string,
...,
orders: OrderModel[]
}
I suppose that with a reduce it could be done easily, but I don't quite understand how it works. Could someone help me with this example?
Reduce can be used but you dont really need it, simple .map
with .filter
and ...
spread operator:
const products = [
{ prod_id: "1", brand: "brand1" },
{ prod_id: "2", brand: "brand1" },
{ prod_id: "3", brand: "brand2" },
{ prod_id: "4", brand: "brand2" },
{ prod_id: "5", brand: "brand3" }
];
const orders = [
{ order_id: "1", prod_id: "1" },
{ order_id: "2", prod_id: "2" },
{ order_id: "3", prod_id: "3" },
{ order_id: "4", prod_id: "3" },
{ order_id: "5", prod_id: "4" }
];
const data = {
products: products,
orders: orders
};
function groupData(data) {
if (!data) return data;
return data.products.map((p) => ({
...p,
orders: data.orders.filter((x) => x.prod_id === p.prod_id)
}));
}
console.log(groupData(data));
Adding a little optimization asked in comments using Map class. With that you will only need 1 loop over initial Orders
array to build the Map
object and then you will have a constant time of element retrieval:
const products = [
{ prod_id: "1", brand: "brand1" },
{ prod_id: "2", brand: "brand1" },
{ prod_id: "3", brand: "brand2" },
{ prod_id: "4", brand: "brand2" },
{ prod_id: "5", brand: "brand3" }
];
const orders = [
{ order_id: "1", prod_id: "1" },
{ order_id: "2", prod_id: "2" },
{ order_id: "3", prod_id: "3" },
{ order_id: "4", prod_id: "3" },
{ order_id: "5", prod_id: "4" }
];
const data = {
products: products,
orders: orders
};
function buildMap(data) {
const res = new Map();
data.orders.forEach((order) => {
if (res.has(order.prod_id)) {
res.get(order.prod_id).push(order);
} else {
res.set(order.prod_id, [order]);
}
});
return res;
}
function groupData(data) {
if (!data) return data;
const ordersMap = buildMap(data);
return data.products.map((p) => ({
...p,
orders: ordersMap.get(p.prod_id) || []
}));
}
console.log(groupData(data));