How can I groupby data with count using lodash javascript
"data": [
{
"id": 27,
"getOrderDetail": [
{
"id": 49,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
},
{
"id": 51,
"order_id": 27,
"product_id": 2,
"product_detail":[...some data...]
}
{
"id": 52,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
}
],
"getOrderStatus": []
},
]
I want to group by product_id in getOrderDetail and count it into qty for example
"data": [
{
"id": 27,
"getOrderDetail": [
{
"id": 49,
"qty": 2,
"order_id": 27,
"product_id": 1,
"product_detail":[...some data...]
},
{
"id": 51,
"order_id": 27,
"qty": 1,
"product_id": 2,
"product_detail":[...some data...]
}
],
"getOrderStatus": []
},
]
I want to do something like this
_.countBy(data, 'getOrderDetail.product_id'); and put data count into qty field
Here is what I try
let result = _.map(totalData, function(totalData, key) {
let mapData = _.groupBy(totalData.getOrderDetail, function({ product_id }) {
return product_id;
});
});
I console.log (mapData) output look like this
{
'1': [
{
id: 49,
product_id: 1,
}
],
'2': [
{
id: 51,
product_id: 2,
}
]
}
still find looking into how can I can conunt qty
You can use _.groupBy() and then map the results, and get the qty by applying _.size() to the group, and get getOrderDetail by merging the group members, concating the arrays, and spreading back to the object:
const data = [{"id":27,"getOrderDetail":[{"id":49,"order_id":27,"product_id":1,"product_detail":[]},{"id":51,"order_id":27,"product_id":2,"product_detail":[]},{"id":52,"order_id":27,"product_id":1,"product_detail":[]}],"getOrderStatus":[]}];
const result = data.map(o => ({
...o,
getOrderDetail: _.map(
_.groupBy(o.getOrderDetail, 'product_id'),
group => ({
qty: _.size(groups),
..._.mergeWith({}, ...groups, (ov, sv) =>
_.isArray(ov) ? ov.concat(sv) : sv
)
})
)
}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Related
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)
I have an array of object and I want to copy that array of object to another array while modifying some items, like copying id only by ascending order and copying only the value of trophies of basketball to trophies. How to do it?
const item = [{
"id": 33,
"name": "John"
"trophies": {
"basketball" : 2,
"baseball" : 5
},
"profile": "profile/212"
}
{
"id": 12,
"name": "Michael"
"trophies": {
"basketball" : 6,
"baseball" : 7
},
"profile": "profile/341"
}
]
I want the above array of object after copying to look something like
const item2 = [{
"id": 12,
"name": "Michael"
"trophies": 6,
"profile": "http://collegeprofile.com/profile/341"
},
{
"id": 33,
"name": "John"
"trophies": 2,
"profile": "http://collegeprofile.com/profile/212"
}
]
You can sort by id ascending order using Array.prototype.sort
And map basketball value to trophies using Array.prototype.map.
const item = [{
"id": 33,
"name": "John",
"trophies": {
"basketball": 2,
"baseball": 5
},
"profile": "profile/212"
}, {
"id": 12,
"name": "Michael",
"trophies": {
"basketball": 6,
"baseball": 7
},
"profile": "profile/341"
}];
const output = item.sort((a, b) => (a.id - b.id)).map((item) => ({
...item,
trophies: item.trophies.basketball,
profile: "http://collegeprofile.com/" + item.profile
}));
console.log(output);
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; }
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>
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.