convert json array based on id - javascript

I want to convert array to another array based on sID and pID properties
the array I have is:
data = [{
{
"sID": 10,
"pID": 5,
"Sum": 9300,
"class": "one",
},{
"sID": 10,
"pID": 5,
"Sum": 2200,
"class": "two",
},{
"sID": 10,
"pID":6 ,
"Sum": 4600,
"class": "one",
},{
"sID": 10,
"pID": 6,
"Sum": 5300,
"class": "two"
}]
I want to create a data in below format
[{"sID":10,"pID":5,"one":9300,"two":2200},
{"sID":10,"pID":6,"one":4600,"two":5300}]
is there a way to do this?

You could take a hash table for same group of keys and assign the sum of the values to the result.
var data = [{ sID: 10, pID: 5, Sum: 9300, class: "one" }, { sID: 10, pID: 5, Sum: 2200, class: "two" }, { sID: 10, pID: 6, Sum: 4600, class: "one" }, { sID: 10, pID: 6, Sum: 5300, class: "two" }],
keys = ['sID', 'pID'],
result = Object.values(data.reduce((h, o) => {
var key = keys.map(k => o[k]).join('|');
if (!h[key]) {
h[key] = Object.assign(...keys.map(k => ({ [k]: o[k] })));
}
h[key][o.class] = (h[key][o.class] || 0) + o.Sum;
return h;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

more basic :
const
data = [
{ "sID": 10, "pID": 5, "Sum": 9300, "class": "one" }
, { "sID": 10, "pID": 5, "Sum": 2200, "class": "two" }
, { "sID": 10, "pID": 6, "Sum": 4600, "class": "one" }
, { "sID": 10, "pID": 6, "Sum": 5300, "class": "two" }
];
var Result = [];
data.forEach(e=>{
let idx = Result.findIndex( k=> k.sID===e.sID && k.pID===e.pID );
if (idx<0)
{
idx = Result.length;
Result.push( { "sID":e.sID, "pID":e.pID });
}
Result[idx][e.class] = e.Sum;
})
console.log( Result )

Related

Javascript array is not somehow mutated

I have an express server which I have GET and POST, and as original state, I have the following:
let orders = [
{
sum: 0,
purchases: [
{
id: 1,
contractId: 55,
value: 100,
},
{
id: 2,
contractId: 55,
value: -100,
}
]
}
]
// this function is running on GET request
export const getOrders = (req, res) => {
reply.status(200).send(orders)
}
export const addOrder = (req, res) => {
const newOrder = req.body
orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
My intention here is to search in the list of orders if the new added order ID is exist, if so, then add it to the list of corresponding purchases, otherwise, create a new object containing a sum and the new order, but whenever I try to add a new order with the same id then it add it to the found contractID PLUS creating a new object containing a sum and new order.
here is an example of what I get after my first POST and then GET:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
}
]
then my second attempts of adding a different order with POST:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
}
]
}
]
then another post and got this results:
[
{
"sum": 100,
"purchases": [
{
"id": 1,
"contractId": 55,
"value": 100
},
{
"id": 2,
"contractId": 55,
"value": -100
},
{
"id": 3,
"contractId": 55,
"value": 100
}
]
},
{
"sum": 200,
"purchases": [
{
"id": 3,
"contractId": 44,
"value": 100
},
{
"id": 4,
"contractId": 44,
"value": 100
}
]
},
{
"sum": 100,
"purchases": [
{
"id": 4,
"contractId": 44,
"value": 100
}
]
}
]
any idea why this weird behavior is happening?
This is because orders.map returns a new object and doesn't mutate the original, you can override the original with:
orders = orders.map((order) => {
const correspondingorder = order.purchases.find(
(purshase) => purshase.contractId === newOrder.contractId
)
if (correspondingorder) {
order.purchases.push(newOrder)
order.sum += newOrder.value
} else {
const newValues = { sum: newOrder.value, purchases: Array(newOrder) }
orders.push(newValues)
}
}
}
But honestly, I don't recommend mutating Objects in this context, because more than 1 request can be reading/writing that variable.
If you really need to use this approach, use Array.forEach and reference the original object instead of map (that returns a new array and doesn't mutate the original one)

Javascript creates new arrays based on conditions

I have old and entity arrays:
var old = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 100,
"yield": 20,
"worth": 30
},
{
"id": 4,
"entity_type_id": 1,
"product_id": 4,
"name": "test2",
"acreage": 10,
"yield": 20,
"worth": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40
}
]
var entity = [
{"id": 1, "name": "a1"},
{"id": 2, "name": "a2"},
{"id": 3, "name": "a3"}
]
I hope to get the following data:
var newArr = [
{
"id": 3,
"entity_type_id": 1,
"product_id": 4,
"name": "test1",
"acreage": 110,
"yield": 40,
"worth": 30,
"entity_type_1": 2, // The total amount of entity_type_id (entity_type_id: 1)
"entity_type_2": 0,
"entity_type_3": 0
},
{
"id": 5,
"entity_type_id": 3,
"product_id": 5,
"name": "test3",
"acreage": 20,
"yield": 20,
"worth": 40,
"entity_type_1": 0,
"entity_type_2": 0,
"entity_type_3": 1 // The total amount of entity_type_id (entity_type_id: 3)
}
]
console.log(newArr)
I tried the following code and got some data. I'm not sure if there will be any exceptions or errors.
What's more, I don't know how to deal with the entity array data. Can someone help me solve this problem and get the result I expect?
Thank you very much !
function mergeArr(arr) {
const temp = []
arr.forEach((dataItem) => {
if (temp.length) {
let filterValue = temp.filter((items) => {
return items.product_id === dataItem.product_id
})
if (filterValue.length) {
temp.forEach((n) => {
if (n.product_id === filterValue[0].product_id) {
n.yield = dataItem.yield + filterValue[0].yield
n.acreage = dataItem.acreage + filterValue[0].acreage
n.worth = dataItem.worth + filterValue[0].worth
}
})
} else {
temp.push(dataItem)
}
} else {
temp.push(dataItem)
}
})
return temp
}
Youi could find the object and sum the wanted properties. For entity take another loop and map new entries and build a new object from it for spreading.
var old = [{ id: 3, entity_type_id: 1, product_id: 4, name: "test1", acreage: 100, yield: 20, worth: 30 }, { id: 4, entity_type_id: 1, product_id: 4, name: "test2", acreage: 10, yield: 20, worth: 0 }, { id: 5, entity_type_id: 3, product_id: 5, name: "test3", acreage: 20, yield: 20, worth: 40 }],
entity = [{ id: 1, name: "a1" }, { id: 2, name: "a2" }, { id: 3, name: "a3" }],
entityTypes = Object.fromEntries(entity.map(({ id }) => ['entity_type_' + id, 0])),
result = old.reduce((r, o) => {
let temp = r.find(q => q.product_id === o.product_id);
if (!temp) r.push(temp = { ... o, ...entityTypes });
else ['acreage', 'yield', 'worth'].forEach(k => temp[k] += o[k]);
temp['entity_type_' + o.entity_type_id]++;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Formatting of JavaScript Objects, Showing Sub Products under Products

I have an array of objects for products I want to show objects that have a parent ID under their parent object with property called subproduct
I have a array object like
let products = [{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "1450",
"name": "Paypal"
},
{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "1451",
"name": "Payments"
}
]
I want to format it in the following way
"products": [{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "14",
"name": "Paypal"
"sub-products": [{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "15",
"name": "Paypal-Payments"
}]
}]
This will work
let products = [
{
"id": 30,
"service_provider_id": 4,
"parent_id": null,
"status_id": 1,
"code": "1450",
"name": "Paypal"
},
{
"id": 31,
"service_provider_id": 4,
"parent_id": 30,
"status_id": 1,
"code": "1451",
"name": "Payments"
}
]
let formated = [];
formated = products.filter(product => product.parent_id == null);
formated.forEach(formatedproduct=>{
products.forEach(product =>{
if(product.parent_id == formatedproduct.id){
if(!formatedproduct.sub_products )
{
formatedproduct.sub_products = [];
}
product.name = formatedproduct.name +' '+product.name;
formatedproduct.sub_products.push(product);
}
});
})
console.log(formated);
You can use a combination of map and reduce
const grouped = [
...products
.sort((a, b) => a.parent_id - b.parent_id)
.reduce((a, b) => a.set(b.parent_id || b.id, (a.get(b.parent_id) || []).concat(b)), new Map())
.values()
]
.map(([f, ...rest]) => (f.sub_products = rest, f));
console.log(grouped);
<script>
const products = [{
'id': 30,
'service_provider_id': 4,
'parent_id': null,
'status_id': 1,
'code': '1450',
'name': 'Paypal'
},
{
'id': 31,
'service_provider_id': 4,
'parent_id': 30,
'status_id': 1,
'code': '1451',
'name': 'Payments'
},
{
'id': 32,
'service_provider_id': 4,
'parent_id': null,
'status_id': 1,
'code': '1450',
'name': 'Paypal'
},
{
'id': 33,
'service_provider_id': 4,
'parent_id': 32,
'status_id': 1,
'code': '1451',
'name': 'Payments'
}
];
</script>

How to flatten and merge nested array from each of child array

So i have this data:
let data = [
{
"purchase_id": 1,
"product": [
{
"name": "A",
"id": 1,
"transactions": [
{
"price": 5,
"qty": 2
},
{
"price": 10,
"qty": 2
}
]
},
{
"name": "B",
"id": 2,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
},
{
"purchase_id": 2,
"product": [
{
"name": "C",
"id": 3,
"transactions": [
{
"price": 5,
"qty": 2
}
]
},
{
"name": "D",
"id": 4,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
}
]
And i want to flatten array from each data.product.transactions data:
"transactions": [
{
"price",
"qty"
}
]
Expected output is:
[
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 5,
"qty": 2
},
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 10,
"qty": 2
},
{
"purchase_id": 1,
"name": "B",
"id": 2,
"price": 3,
"qty": 4
},
{
"purchase_id": 2,
"name": "C",
"id": 3,
"price": 5,
"qty": 2
},
{
"purchase_id": 2,
"name": "D",
"id": 4,
"price": 3,
"qty": 4
},
]
I have tried to use object assign, reduce but my code doesn't work. Thank you
Use nested Array.map() to create the objects, and spread into Array.concat() to flatten the sub-arrays at each level:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [].concat(...data.map(({ purchase_id, product }) =>
[].concat(...product.map(({ name, id, transactions }) =>
transactions.map((o) => ({
purchase_id,
name,
id,
...o
})
)))));
console.log(result);
If you want to avoid the temp sub-arrays, and the flattering, use nested Array.forEach() calls, and push the created objects to a predefined array:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [];
data.forEach(({ purchase_id, product }) =>
product.forEach(({ name, id, transactions }) =>
transactions.forEach((o) => result.push({
purchase_id,
name,
id,
...o
})
)));
console.log(result);
var arr = [];
data.forEach(x => {
x.product.forEach(y => {
y.transactions.forEach(z => {
z["name"] = y.name;
z["id"] = y.id;
z["purchase_id"] = x.purchase_id;
arr.push(z);
});
})
});
console.log(arr);

lodash merge and combine objects

I have an array of objects as below that I read from my database using sequelize ORM:
I want to have all my videos from a section, but the better I can return using sequelize is :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
}
},
{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": {
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
}
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": {
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}
}]
Is there a way to merge and combine the objects in my array to obtain something like this :
[{
"id": 2,
"name": "Ru",
"subsection": 1,
"Video": [{
"id": 11,
"source": "sourrrccrsss22222",
"videoSubSection": 2
},{
"id": 12,
"source": "sourrrccrsss111",
"videoSubSection": 2
}]
},
{
"id": 1,
"name": "Oc",
"subsection": 1,
"Video": [{
"id": 13,
"source": "sourrrcc",
"videoSubSection": 1
},{
"id": 14,
"source": "sourrrcc",
"videoSubSection": 1
}]
}
The function that approach the most is _.mergeWith(object, sources, customizer) but the main problem I have is that I have on object and need to merge this object.
In plain Javascript, you can use Array#forEach() with a temporary object for the arrays.
var data = [{ id: 2, name: "Ru", subsection: 1, Video: { id: 11, source: "sourrrccrsss22222", VideoSubSection: 2 } }, { id: 2, name: "Ru", subsection: 1, Video: { id: 12, source: "sourrrccrsss111", VideoSubSection: 2 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 13, source: "sourrrcc", VideoSubSection: 1 } }, { id: 1, name: "Oc", subsection: 1, Video: { id: 14, source: "sourrrcc", VideoSubSection: 1 } }],
merged = function (data) {
var r = [], o = {};
data.forEach(function (a) {
if (!(a.id in o)) {
o[a.id] = [];
r.push({ id: a.id, name: a.name, subsection: a.subsection, Video: o[a.id] });
}
o[a.id].push(a.Video);
});
return r;
}(data);
document.write('<pre>' + JSON.stringify(merged, 0, 4) + '</pre>');
Maybe try transform():
_.transform(data, (result, item) => {
let found;
if ((found = _.find(result, { id: item.id }))) {
found.Video.push(item.Video);
} else {
result.push(_.defaults({ Video: [ item.Video ] }, item));
}
}, []);
Using reduce() would work here as well, but transform() is less verbose.
You can do it this way (test is your db output here)
var result = [];
var map = [];
_.forEach(test, (o) => {
var temp = _.clone(o);
delete o.Video;
if (!_.some(map, o)) {
result.push(_.extend(o, {Video: [temp.Video]}));
map.push(o);
} else {
var index = _.findIndex(map, o);
result[index].Video.push(temp.Video);
}
});
console.log(result); // outputs what you want.

Categories

Resources