Get object value based on conditions within nested array objects - javascript

I have an array of objects called orders:
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}
]
}
];
I need to get the quantity when both the order_type (Wholesale) and items.detail.ID (13363) match.
I have so far tried the following:
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if(item.detail.ID == 13363) {
return item.quantity;
}
}, 0);
Where result correctly returns 4
My issue, and I'm sure I am missing something very simple is that when I have multiple items in my orders array, it fails.
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
},
{
"id": 56,
"department": "Womens",
"type": "Skirt",
"quantity": 12,
"detail": {
"ID": 76884,
"On Sale": 0,
}
},
{
"id": 89,
"department": "Mens",
"type": "Shirts",
"quantity": 20,
"detail": {
"ID": 98223,
"On Sale": 1,
}
}
]
}
];
The same
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if(item.detail.ID == 13363) {
return item.quantity;
}
}, 0);
returns undefined
Thank you

The find helper just returns the first match, so you need to use another helper like filter, like this:
const ID = 13363;
const result = orders
.filter((order) => order.order_type === 'Wholesale')
.reduce((acc, curr) => {
const items = curr.items.filter((item) => item.detail.ID === ID);
console.log(items);
// You can sum the matching items and then push them into the acc array
const quantity = items.reduce((sum, item) => (sum += item.quantity), 0);
acc.push(quantity);
return acc;
}, []);
This will return an array of matching quantities.

Not sure about the use case but here you go
const result = orders.find(item => item.order_type == "Wholesale").items
.reduce((total, item) => {
if (item.detail.ID == 13363) {
total += item.quantity;
}
return total
}, 0);

You can even create a function to make the search dynamic.
const orders = [
{
"order_id": 47445,
"order_type": "Wholesale",
"items": [
{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
},
{
"id": 56,
"department": "Womens",
"type": "Skirt",
"quantity": 12,
"detail": {
"ID": 76884,
"On Sale": 0,
}
},
{
"id": 89,
"department": "Mens",
"type": "Shirts",
"quantity": 20,
"detail": {
"ID": 98223,
"On Sale": 1,
}
}
]
}
];
findMyItem=( ID )=>{
var result = null ;
const result2 = orders.find(item => item.order_type == "Wholesale").items
.map(( item) => {
if(item.detail.ID == ID ) {
result = item.quantity;
}
}, 0);
return result ;
}
console.log( "result" ,findMyItem( 13363 ) )
console.log( "result" ,findMyItem( 98223) )
console.log( "result" ,findMyItem( 76884) )

You could use Array.find() on the orders array to find the correct order, searching for the first order that matches both the order_type and has an item matching the desired itemId (using Array.some()).
If this order exists, we can then find the corresponding item quantity using .find() again,
const orders = [ { "order_id": 47445, "order_type": "Wholesale", "items": [ { "id": 9, "department": "Womens", "type": "Dress", "quantity": 4, "detail": { "ID": 13363, "On Sale": 1, } }, { "id": 56, "department": "Womens", "type": "Skirt", "quantity": 12, "detail": { "ID": 76884, "On Sale": 0, } }, { "id": 89, "department": "Mens", "type": "Shirts", "quantity": 20, "detail": { "ID": 98223, "On Sale": 1, } } ] } ]
function findItemQuantity(orders, orderType, itemId) {
// Find the first order with the right order_type and containing the right item id
const order = orders.find(order => order.order_type = orderType && order.items.some(item => item.detail.ID === itemId));
if (!order) {
return null;
}
const item = order.items.find(item => item.detail.ID === itemId);
if (!item) {
return null;
}
return item.quantity;
}
console.log("Quantity found:", findItemQuantity(orders, 'Wholesale', 13363))
console.log("Quantity found:", findItemQuantity(orders, 'Wholesale', 76884))

const result = orders
.filter(order => order.order_type == "Wholesale")
.map(order => order.items.find(item => item.detail.ID == 13363))
.filter(item => item)
.reduce((total, { quantity }) => quantity + total, 0);

const orders = [{
"order_id": 47445,
"order_type": "Wholesale",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
},
{
"order_id": 47445,
"order_type": "Whole",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
}
]
const result = orders.reduce(v => {
return v.items.map(a => {
if (v.order_type == 'Wholesale' && a.detail.ID == 13363) {
return v
}
})
})
console.log(result)

const orders = [{
"order_id": 47445,
"order_type": "Wholesale",
"items": [{
"id": 9,
"department": "Womens",
"type": "Dress",
"quantity": 4,
"detail": {
"ID": 13363,
"On Sale": 1,
}
}]
}];
var result = null;
const result2 = orders.find(item => item.order_type == "Wholesale").items
.map((item) => {
if (item.detail.ID == 98223) {
result = item.quantity;
}
}, 0);
console.log("result", result)

Related

Sort Ids that are only numbers in an array of objects

I have an JSON file with data inside of an user
[
{
"_id": "62bd5fba34a8f1c90303055c",
"index": 0,
"email": "mcdonaldholden#xerex.com",
"nameList": [
{
"id": 0,
"name": "Wendi Mooney"
},
{
"id": 2,
"name": "Holloway Whitehead"
}
]
},
{
"_id": "62bd5fbac3e5a4fca5e85e81",
"index": 1,
"nameList": [
{
"id": 0,
"name": "Janine Barrett"
},
{
"id": 1,
"name": "Odonnell Savage"
},
{
"id": 2,
"name": "Patty Owen"
}
]
},
{
"_id": "62bd5fbaf8f417d849c135db",
"index": 2,
"email": "pattyowen#xerex.com",
"nameList": [
{
"id": 0,
"name": "Earline Goff"
},
{
"id": 1,
"name": "Glenna Lawrence"
},
{
"id": 7,
"name": "Bettye Sawyer"
}
]
I had to sort every user by : if user has more than two names
if user ids are consecutive
and if user ids are numbers
I managed to sort user by more than two names and if ids are consecutive
userData.filter(({nameList}) =>
nameList.length > 2 &&
!nameList.some(({id}, index, array) => index && array[index - 1].id !== id - 1)
);
In the case that an object has an id as number I should not return the objects. How can I implement that in my code?
The output is expected to be all the arrays that meet the filter, and some() criteria. Which is if objects has more than 2 names, its ids are consecutive and the ids should be a number.
If you want to check if the id is of type number:
(typeof id == "number")
To check if can be cast to a number
(id == parseInt(id, 10))
The complete code then (you were close):
var userData = get_data();
userData = userData.filter(function(item) {
return item.nameList.length > 2 &&
item.nameList.every(function(item, index, arr) {
return parseInt(item.id) == item.id && (index == 0 || item.id - arr[index - 1].id == 1)
})
})
console.log(userData);
function get_data() {
return [{
"_id": "62bd5fba34a8f1c90303055c",
"index": 0,
"email": "mcdonaldholden#xerex.com",
"nameList": [{
"id": 0,
"name": "Wendi Mooney"
},
{
"id": 2,
"name": "Holloway Whitehead"
}
]
},
{
"_id": "62bd5fbac3e5a4fca5e85e81",
"index": 1,
"nameList": [{
"id": 0,
"name": "Janine Barrett"
},
{
"id": 1,
"name": "Odonnell Savage"
},
{
"id": 2,
"name": "Patty Owen"
}
]
},
{
"_id": "62bd5fbaf8f417d849c135db",
"index": 2,
"email": "pattyowen#xerex.com",
"nameList": [{
"id": 0,
"name": "Earline Goff"
},
{
"id": 1,
"name": "Glenna Lawrence"
},
{
"id": 7,
"name": "Bettye Sawyer"
}
]
}
];
}
.as-console-wrapper {
max-height: 100% !important
}

How can I filter the array of objects by: if object ids are consective

I have a JSON file with data inside.
I have to filter the data by : if user has more than two names, and if user ids are consecutive.
The JSON file :
[
{
"_id": "62bd5fba34a8f1c90303055c",
"index": 0,
"email": "mcdonaldholden#xerex.com",
"nameList": [
{
"id": 0,
"name": "Wendi Mooney"
},
{
"id": 2,
"name": "Holloway Whitehead"
}
]
},
{
"_id": "62bd5fbac3e5a4fca5e85e81",
"index": 1,
"nameList": [
{
"id": 0,
"name": "Janine Barrett"
},
{
"id": 1,
"name": "Odonnell Savage"
},
{
"id": 2,
"name": "Patty Owen"
}
]
}, ...
I have managed to find an a solution to filter if the users have more than two names : userData.filter((names,i) => { return names?.nameList?.filter(names => { return names.name;}).length > 2 ; })
But I cant seem to grasp myself around the concept of filtering the consecutive ids.
Also I was advised to not use any for loops at all. Only ES6 array loops like map, forEach and filter.
Here's a solution that uses every() to compare the ID of every element with the previous ID:
const result = data.filter(({nameList}) =>
nameList.length > 2 &&
nameList.every(({id}, i, a) => !i || id === a[i - 1].id + 1)
);
Complete snippet:
const data = [{
"_id": "62bd5fba34a8f1c90303055c",
"index": 0,
"email": "mcdonaldholden#xerex.com",
"nameList": [{
"id": 0,
"name": "Wendi Mooney"
}, {
"id": 2,
"name": "Holloway Whitehead"
}]
}, {
"_id": "62bd5fbac3e5a4fca5e85e81",
"index": 1,
"nameList": [{
"id": 0,
"name": "Janine Barrett"
}, {
"id": 1,
"name": "Odonnell Savage"
}, {
"id": 2,
"name": "Patty Owen"
}]
}];
const result = data.filter(({nameList}) =>
nameList.length > 2 &&
nameList.every(({id}, i, a) => !i || id === a[i - 1].id + 1)
);
console.log(result);

How to group by and sum an array of objects javascript?

const array = [
{
"data": {
"qty": "5",
"toy": {
"id": 3,
},
"available": "yes",
}
},
{
"data": {
"qty": "5",
"toy": {
"id": 10,
},
"available": "no"
}
},
{
"data": {
"qty": "59",
"toy": {
"id": 10,
},
"available": "yes",
}
},
{
"data": {
"qty": "5",
"toy": {
"id": 3,
},
"available": "yes",
}
}
]
var result = [];
array.reduce(function(res, value) {
if (!res['data']['toy'] || !res['data']['toy']['data']) {
res['data'] = {...value['data'] };
result.push(res['data'])
}
if (res['data']['available'] === value['data']['available'] && res['data']['toy']['id'] === value['data']['toy']['id']) {
res['data']['qty'] = parseInt(res['data']['qty']) + parseInt(value['data'].qty)
}
return res;
}, {'data': {}});
console.log(result)
I am working on a js project and I need a bit of help here. From the array, How to get a new array that has qty as the sum of the other qty value which data.toy.id and available same. i.e. I want the below array. My code is not working as excepted. Changes to the same or new code are also fine. Thank you.
const array = [
{
"data": {
"qty": "10",
"toy": {
"id": 3,
},
"available": "yes",
}
},
{
"data": {
"qty": "5",
"toy": {
"id": 10,
},
"available": "no"
}
},
{
"data": {
"qty": "59",
"toy": {
"id": 10,
},
"available": "yes",
}
}
]
You group the array into an object, where the keys are concatenation of available and id properties and finally transform the object back to an array using Object.values.
const
array = [
{ data: { qty: "5", toy: { id: 3 }, available: "yes" } },
{ data: { qty: "5", toy: { id: 10 }, available: "no" } },
{ data: { qty: "59", toy: { id: 10 }, available: "yes" } },
{ data: { qty: "5", toy: { id: 3 }, available: "yes" } },
],
result = Object.values(
array.reduce((r, { data }) => {
const k = data.available + data.toy.id;
if (r[k]) {
r[k].data.qty = String(Number(r[k].data.qty) + Number(data.qty));
} else {
r[k] = { data };
}
return r;
}, {})
);
console.log(result);
I'd suggest using Array.reduce() to group by a key, which will be combined value of the toy id and the available property.
We'd create a map of all toys based on this key, summing the quantity for each.
Finally, we'll use Object.values() to convert back into an array.
const array = [ { "data": { "qty": "5", "toy": { "id": 3, }, "available": "yes", } }, { "data": { "qty": "5", "toy": { "id": 10, }, "available": "no" } }, { "data": { "qty": "59", "toy": { "id": 10, }, "available": "yes", } }, { "data": { "qty": "5", "toy": { "id": 3, }, "available": "yes", } } ];
const result = Object.values(array.reduce((acc, { data: { qty, toy, available } }) => {
const key = `${toy.id}-${available}`;
acc[key] = acc[key] || { data: { qty: 0, toy, available } };
acc[key].data.qty += Number(qty);
return acc;
}, {}))
console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }
You can use Array#reduce() to create arrayHash object using as keys: ${c.data.toy.id}-${c.data.available}
Code:
const array = [{data: {qty: '5',toy: {id: 3,},available: 'yes',},},{data: {qty: '5',toy: {id: 10,},available: 'no',},},{data: {qty: '59',toy: {id: 10,},available: 'yes',},},{data: {qty: '5',toy: {id: 3,},available: 'yes',},},]
const arrayHash = array.reduce((a, { data }) => {
const key = `${data.toy.id}-${data.available}`
a[key] = a[key] || { data: { ...data, qty: 0 } }
a[key].data.qty = (+a[key].data.qty + +data.qty).toString();
return a
}, {})
const result = Object.values(arrayHash)
console.log(result)
I'd use just reduce
const a1 = [
{
"data": {
"qty": "5",
"toy": {
"id": 3,
},
"available": "yes",
}
},
{
"data": {
"qty": "5",
"toy": {
"id": 10,
},
"available": "no"
}
},
{
"data": {
"qty": "59",
"toy": {
"id": 10,
},
"available": "yes",
}
},
{
"data": {
"qty": "5",
"toy": {
"id": 3,
},
"available": "yes",
}
}
]
const a2 = a1.reduce((acc, it) => {
let found = acc.find(
dp => dp.data.toy.id === it.data.toy.id && dp.data.available === it.data.available
)
if(found){
found.data.qty = ( Number(found.data.qty) + Number(it.data.qty) ).toString()
}
else acc.push(it)
return acc
}, [])
console.log(JSON.stringify(a2, null,2))

Group an array of objects based on a specific field

I have an array of objects. I want to group them by a specific field.
[
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
]
The output I expect for grouping by name attribute is as follows.
{
// Group #1
"JOHN": [
{
"type": 2,
"sum": 200
}
{
"type": 1,
"sum": 5
}
],
// Group #2
"SERA":[
{
"type": 1,
"sum": 43
},
{
"type": 2,
"sum": 129
},
]
}
I used nested loops, but unfortunately the execution speed was slow and it did not give the right results.
As if you mentioned, we can use an object instead of an array for the most outer wrapper. And also swap inside one object to an array, then this is a possible solution.
var data = [{"name": "JOHN","type": 1,"sum": 5},{"name": "SERA","type": 1,"sum": 43},{"name": "SERA","type": 2,"sum": 129},{"name": "JOHN","type": 2,"sum": 200}];
var newData = {};
data.forEach( (item) => {
if (!(item['name'] in newData)) {
newData[item['name']] = [];
}
newData[item['name']].push(
{
'type': item['type'],
'sum' : item['sum']
}
);
});
console.log(newData);
Your proposed output structure is not valid, however using Array.reduce you can create an object in which all the properties are arrays of objects:
const data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
const result = data.reduce((c, {name, type, sum}) => {
c[name] = c[name] || [];
c[name].push({type, sum});
return c;
}, {});
console.log(result);
One more way with forEach, destructuring and ?? operator
const merge = (arr) => {
const obj = {};
arr.forEach(({ name, ...rest }) => (obj[name] ??= []).push(rest));
return obj;
};
const data = [
{
name: "JOHN",
type: 1,
sum: 5,
},
{
name: "SERA",
type: 1,
sum: 43,
},
{
name: "SERA",
type: 2,
sum: 129,
},
{
name: "JOHN",
type: 2,
sum: 200,
},
];
console.log(merge(data));
You can use this function which take advantage of Array.prototype.reduce to transform the initial data to another structure of array.
let data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
function groupedBy(data, field) {
let fieldValues = [...data].reduce((acc, current) => {
return acc.concat(current[field]);
}, []).filter((value, index, self) => {
return self.indexOf(value) === index;
});
let results = fieldValues.reduce((acc, item) => {
let items = [...data].filter(el => {
return el.name === item;
});
items.forEach(i => delete i.name);
return Object.assign(acc, { [item]: items});
}, {});
return results;
}
console.log(groupedBy(data, "name"));

How to find a value in multilevel Array of objects

I'm trying to implement a search box in which if i start searching for a value it will look for the target in an nested array of objects which is like this:--
[
{
"groupId": 1,
"groupName": "Americas",
"groupItems": [
{
"id": 5,
"name": "Brazil",
"parentID": 1,
"parentName": "Americas"
},
{
"id": 6,
"name": "Canada",
"parentID": 1,
"parentName": "Americas"
}
],
"isExpanded": false,
"toggleAllSelection": false
},
{
"groupId": 2,
"groupName": "APAC",
"groupItems": [
{
"id": 7,
"name": "Australia",
"parentID": 2,
"parentName": "APAC"
},
{
"id": 8,
"name": "China",
"parentID": 2,
"parentName": "APAC"
}
],
"isExpanded": false,
"toggleAllSelection": false
},
{
"groupId": 3,
"groupName": "Europe",
"groupItems": [
{
"id": 9,
"name": "Belgium",
"parentID": 3,
"parentName": "Europe"
},
{
"id": 7,
"name": "Austria",
"parentID": 2,
"parentName": "APAC"
},
{
"id": 10,
"name": "Bulgaria",
"parentID": 3,
"parentName": "Europe"
}
],
"isExpanded": false,
"toggleAllSelection": false
}
]
Now i want to search for name property in each groupItems array of objects in group array. and when there is a match my function should return data in same format and as it will be autocomplete so instead of exact match it should be partial match. So if search aus in input box it should return
[{
"groupId": 2,
"groupName": "APAC",
"groupItems": [
{
"id": 7,
"name": "Australia",
"parentID": 2,
"parentName": "APAC"
}],
"isExpanded": false,
"toggleAllSelection": false,
},
{
"groupId": 3,
"groupName": "Europe",
"groupItems": [
{
"id": 7,
"name": "Austria",
"parentID": 2,
"parentName": "APAC"
}
],
"isExpanded": false,
"toggleAllSelection": false
}
]
const findByName = (data, name) => {
const result = data.reduce((m, { groupItems, ...rest }) => {
let mapGrpItems = (groupItems || []).filter((item) =>
item.name.includes(name)
);
if (mapGrpItems.length) {
m.push({ ...rest, groupItems: mapGrpItems });
}
return m;
}, []);
return result;
};
const findByName = (data, name) => {
const result = data.reduce((m, { groupItems, ...rest }) => {
let mapGrpItems = (groupItems || []).filter((item) =>
item.name.includes(name)
);
if (mapGrpItems.length) {
m.push({ ...rest, groupItems: mapGrpItems });
}
return m;
}, []);
return result;
};
const data = [{"groupId":1,"groupName":"Americas","groupItems":[{"id":5,"name":"Brazil","parentID":1,"parentName":"Americas"},{"id":6,"name":"Canada","parentID":1,"parentName":"Americas"}],"isExpanded":false,"toggleAllSelection":false},{"groupId":2,"groupName":"APAC","groupItems":[{"id":7,"name":"Australia","parentID":2,"parentName":"APAC"},{"id":8,"name":"China","parentID":2,"parentName":"APAC"}],"isExpanded":false,"toggleAllSelection":false},{"groupId":3,"groupName":"Europe","groupItems":[{"id":9,"name":"Belgium","parentID":3,"parentName":"Europe"},{"id":7,"name":"Austria","parentID":2,"parentName":"APAC"},{"id":10,"name":"Bulgaria","parentID":3,"parentName":"Europe"}],"isExpanded":false,"toggleAllSelection":false}]
console.log(JSON.stringify(findByName(data, "Aus"), null, 2));
I would definitely attempt to reason through what you're trying to do before just implementing this. Being able to reason through solutions like this is 99% of the job when it comes to programming.
function filterGroups(filter) {
const result = [];
myObj.forEach(group => {
const filteredGroups = group.groupItems.filter(groupItem => {
return groupItem.name.toLowerCase().includes(filter);
});
if (filteredGroups.length > 1) {
result.push({
...group,
groupItems: filteredGroups
});
}
});
return result;
}
You can use Arrays.filter for the group items in each outer object in your JSON array to filter out the items which match your search query. You can write something like this:
let autocomplete = (key) => {
// arr = Your Data
let result = []
arr.forEach(grp=> {
let out = grp
let res = grp.groupItems.filter(item => item.name.toLowerCase().includes(key.toLowerCase()))
if(res.length!=0)
{
out.groupItems = res
result.push(out)}
})
return result

Categories