Related
I have a 2D array where the outer array contains objects, each of which contains another array of objects. Here is the data:
const companies = [{
companyId: 100,
companyName: "Company 1",
transactions: [
{ id: "10421", date: "09/19/2022", selected: true, },
{ id: "00467", date: "05/08/2022", selected: true, },
],
},
{
companyId: 200,
companyName: "Company 2",
transactions: [
{ id: "259A6", date: "01/11/2022", selected: false, },
{ id: "87K37", date: "04/14/2022", selected: false, },
],
},
];
I want to get the list of transactions that have their selected fields set to true. This is how I am filtering the data:
const selectedTransactions = companies.filter((c) =>
c.transactions.filter((t) => t.selected === true));
Instead of getting the transactions of only the first company, I'm getting the transactions of ALL companies, including the ones that are not selected. Am I making a mistake somewhere?
You could flat-map the overall companies; then internally filter and map the transaction IDs and dates along with the company ID.
const companies = [{
companyId: 100,
companyName: "Company 1",
transactions: [
{ id: "10421", date: "09/19/2022", selected: true },
{ id: "00467", date: "05/08/2022", selected: true },
],
}, {
companyId: 200,
companyName: "Company 2",
transactions: [
{ id: "259A6", date: "01/11/2022", selected: false },
{ id: "87K37", date: "04/14/2022", selected: false },
],
}];
const selected = companies
.flatMap(({ companyId, transactions }) => transactions
.filter(({ selected }) => selected)
.map(({ id: transactionId, date: transactionDate }) =>
({ companyId, transactionId, transactionDate })));
console.log(selected);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Result
[
{ "companyId": 100, "transactionId": "10421", "transactionDate": "09/19/2022" },
{ "companyId": 100, "transactionId": "00467", "transactionDate": "05/08/2022" }
]
If youre just looking for the transactions you could use map, though it does return a second empty array. Or just add a little to your filter function to get only the company with what youre looking for.
const companies = [{
companyId: 100,
companyName: "Company 1",
transactions: [
{ id: "10421", date: "09/19/2022", selected: true },
{ id: "00467", date: "05/08/2022", selected: true },
],
}, {
companyId: 200,
companyName: "Company 2",
transactions: [
{ id: "259A6", date: "01/11/2022", selected: false },
{ id: "87K37", date: "04/14/2022", selected: false },
],
}];
// USING MAP TO GET TRANSACTIONS
const st = companies.map(c => c.transactions.filter(t => t.selected === true))
console.log(st);
// USING FILTER TO GET COMPANY
const selectedTransactions = companies.filter(c => {
c.transactions = c.transactions.filter(t => t.selected === true);
if (c.transactions.length) return c;
});
console.log(selectedTransactions);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Result
1
[
[
{
"id": "10421",
"date": "09/19/2022",
"selected": true
},
{
"id": "00467",
"date": "05/08/2022",
"selected": true
}
],
[]
]
2
[
{
"companyId": 100,
"companyName": "Company 1",
"transactions": [
{
"id": "10421",
"date": "09/19/2022",
"selected": true
},
{
"id": "00467",
"date": "05/08/2022",
"selected": true
}
]
}
]
I can't figure out how to properly use .filter() to find an object in an Array by searching for a value in its nested Array.
I have the following data:
const orders = [
{
id: 1,
items: [
{
itemId: "abc",
},
{
itemId: "def",
},
],
},
{
id: 2,
items: [
{
itemId: "jkl",
},
{
itemId: "mno",
},
],
},
{
id: 3,
items: [
{
itemId: "abc",
},
{
itemId: "xyz",
},
],
},
];
I have the needed itemId: "abc" which I need to use to find all the objects that have items that also have the Id of "abc", so that the result is this:
[
{
id: 1,
items: [
{
itemId: "abc",
},
{
itemId: "def",
},
],
},
{
id: 3,
items: [
{
itemId: "abc",
},
{
itemId: "xyz",
},
],
},
]
So far, I've tried the following:
orders &&
orders.filter((order) => {
return order.items.filter((item) => item.itemId === "abc");
});
But it doesn't seem to work. What am I missing here?
Chris G beat me to it in the comments but he is right, you need to use order.items.some in your inner function:
const orders = [{
id: 1,
items: [{
itemId: "abc",
},
{
itemId: "def",
},
],
},
{
id: 2,
items: [{
itemId: "jkl",
},
{
itemId: "mno",
},
],
},
{
id: 3,
items: [{
itemId: "abc",
},
{
itemId: "xyz",
},
],
},
]
var ans = orders.filter((order) => {
return order.items.some((item) => item.itemId === "abc");
});
console.log(ans)
const orders = [{
id: 1,
items: [{
itemId: "abc",
},
{
itemId: "def",
},
],
},
{
id: 2,
items: [{
itemId: "jkl",
},
{
itemId: "mno",
},
],
},
{
id: 3,
items: [{
itemId: "abc",
},
{
itemId: "xyz",
},
],
},
];
const result = orders.filter(order =>
order.items.find(item => item.itemId === 'abc') !== undefined
)
console.log(result);
I have an object that looks like this:
{
data: [
{ id: "1", state: "accepted", estimate_date: "2019-12-17" },
{ id: "2", state: "rejected", estimate_date: "2019-12-17" },
{ id: "3", state: "open", estimate_date: "2019-12-17" },
{ id: "4", state: "open", estimate_date: "2019-12-18" },
{ id: "5", state: "rejected", estimate_date: "2019-12-18" },
{ id: "6", state: "accepted", estimate_date: "2019-12-18" },
]
}
When I use lodash groupBy on the object like this:
const key = 'data';
const groupedEstimates = groupBy(estimateData[key], 'estimate_date');
It returns:
[
[
"2019-12-17"
],
[
[ { id: "1", state: "accepted" } ],
[ { id: "2", state: "rejected" } ],
[ { id: "3", state: "open" } ]
]
],
[
[
"2019-12-18"
],
[
[ { id: "4", state: "open" } ],
[ { id: "5", state: "rejected" } ],
[ { id: "6", state: "accepted" } ]
]
]
But now I'm trying to achieve something like this:
[
{
date: "2019-12-17",
items: [
{ id: "1", state: "accepted" },
{ id: "2", state: "rejected" },
{ id: "3", state: "open" },
]
},
{
date: "2019-12-18",
items: [
{ id: "4", state: "open" },
{ id: "5", state: "rejected" },
{ id: "6", state: "accepted" },
]
}
]
Except I don't know how to achieve that using lodash. It doesn't have to use lodash but I only used that at the start as it seemed an easy solution to my problem. Now that I'm trying to achieve a more sensible data structure I would like some insights on how to achieve it.
After grouping by the estimate_date property, iterate the groups object with _.map(). Generate the group's object by taking the key (2nd param) for the date property, and mapping the items to omit the estimate_date:
const estimateData = {"data":[{"id":"1","state":"accepted","estimate_date":"2019-12-17"},{"id":"2","state":"rejected","estimate_date":"2019-12-17"},{"id":"3","state":"open","estimate_date":"2019-12-17"},{"id":"4","state":"open","estimate_date":"2019-12-18"},{"id":"5","state":"rejected","estimate_date":"2019-12-18"},{"id":"6","state":"accepted","estimate_date":"2019-12-18"}]}
const groupedEstimates = _.map(
_.groupBy(estimateData.data, 'estimate_date'),
(items, date) => ({
date,
items: items.map(o => _.omit(o, 'estimate_date'))
})
)
console.log(groupedEstimates)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
I have below JSON data set
[
{
"campaignId": 111,
"campaignCategory": "Diabetes",
"result": [
{
"campaignType": 1,
"name": "tes1"
},
{
"campaignType": 1,
"name": "test22"
},
{
"campaignType": 3,
"name": "test33"
}
]
},
{
"campaignId": 222,
"campaignCategory": "Orthopedic",
"result": [
{
"campaignType": 1,
"name": "Orthopedic"
}
]
},
{
"campaignId": 333,
"campaignCategory": "Cardiology",
"result": [
{
"campaignType": 3,
"name": "Cardiology"
},
{
"campaignType": 1,
"name": "Cardiology 123"
}
]
}
]
I have tired below filter but that doesn't returned desired data.
_.filter(summary, function (data) {
return (post, _.filter(data.result, {'campaignType': 3}));
I want to get below data after filtering applied.
[{ campaignId: 111, campaignCategory: 'Diabetes', result: [{
campaignType: 3, name: 'test33'
}] },
{ campaignId: 333, campaignCategory: 'Cardiology', result: [{
campaignType: 3, name: 'Cardiology'
}] } ];
Here all the nodes are showing which have campaignType: 3.
Lodash or pure java-script based solution will work.
You can use reduce to find objects which have a .result item with a campaignType of 3, and if found, push them to the accumulator array:
const getOutput = () => {
const output = arr.reduce((a, item) => {
const foundResults = item.result.filter(({ campaignType }) => campaignType === 3);
if (foundResults.length) {
a.push({ ...item, result: foundResults });
}
return a;
}, []);
console.log(output);
};
const arr = [{
campaignId: 111,
campaignCategory: 'Diabetes',
result: [{
campaignType: 1,
name: 'tes1'
}, {
campaignType: 1,
name: 'test22'
}, {
campaignType: 3,
name: 'test33'
}]
},
{
campaignId: 222,
campaignCategory: 'Orthopedic',
result: [{
campaignType: 1,
name: 'Orthopedic'
}]
},
{
campaignId: 333,
campaignCategory: 'Cardiology',
result: [{
campaignType: 3,
name: 'Cardiology'
},
{
campaignType: 1,
name: 'Cardiology 123'
}
]
}
];
getOutput();
You could filter the inner result in advance and take the outer objects if ayn filters elements exists. Then take a new object with a new result.
var data = [{ campaignId: 111, campaignCategory: 'Diabetes', result: [{ campaignType: 1, name: 'tes1' }, { campaignType: 1, name: 'test22' }, { campaignType: 3, name: 'test33' }] }, { campaignId: 222, campaignCategory: 'Orthopedic', result: [{ campaignType: 1, name: 'Orthopedic' }] }, { campaignId: 333, campaignCategory: 'Cardiology', result: [{ campaignType: 3, name: 'Cardiology' }, { campaignType: 1, name: 'Cardiology 123' }] }],
result = data.reduce((r, o) => {
var result = o.result.filter(({ campaignType}) => campaignType === 1);
if (result.length) r.push(Object.assign({}, o, { result }));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use filter with some and map in vanilla javascript.
var data = [{ campaignId: 111, campaignCategory: 'Diabetes', result: [{
campaignType: 1, name: 'tes1'
},{
campaignType: 1, name: 'test22'
},{
campaignType: 3, name: 'test33'
}] },
{ campaignId: 222, campaignCategory: 'Orthopedic', result: [{
campaignType: 1, name: 'Orthopedic'
}] },
{ campaignId: 333, campaignCategory: 'Cardiology', result: [{
campaignType: 3, name: 'Cardiology'
},
{
campaignType: 1, name: 'Cardiology 123'
}]} ];
var res = data.filter(campaign => campaign.result.some(type => type.campaignType === 3));
res = res.map(campaign => {
campaign.result = campaign.result.filter(type => type.campaignType ===3);
return campaign;
});
console.log(res);
It seems to me you can get this result with a simple Array.reduce and Array.forEach like this:
let data = [{ "campaignId": 111, "campaignCategory": "Diabetes", "result": [{ "campaignType": 1, "name": "tes1" }, { "campaignType": 1, "name": "test22" }, { "campaignType": 3, "name": "test33" } ] }, { "campaignId": 222, "campaignCategory": "Orthopedic", "result": [{ "campaignType": 1, "name": "Orthopedic" }] }, { "campaignId": 333, "campaignCategory": "Cardiology", "result": [{ "campaignType": 3, "name": "Cardiology" }, { "campaignType": 1, "name": "Cardiology 123" } ] } ]
let result = data.reduce((r,{result,...rest}) => {
result.forEach(x => x.campaignType === 3 ? r.push({...rest, result:[x]}) : null)
return r
}, [])
console.log(result)
I have a complex JavaScript object given below.
An example object:
var object= {
"name": "tfifkhul",
"id": "262761",
"children": [
{
"name": "rthrth",
"id": 0,
"children": [
{
"name": "test",
"id": "262762",
"children": []
}
]
},
{
"name": "rthsrth",
"id": 0,
"children": [
{
"name": "test",
"id": "262762",
"children": []
}
]
},
{
"name": "rthrthhrth",
"id": 0,
"children": [
{
"name": "test",
"id": "262762",
"children": [
{
"name": "rtjrtj",
"id": 0,
"children": [
{
"name": "fwefwefwef",
"id": "262768",
"children": []
}
]
},
{
"name": "hsrtjrtdjrtj",
"id": 0,
"children": [
{
"name": "we4yhesrhy",
"id": "262764",
"children": []
}
]
},
{
"name": "lol",
"id": "262763",
"children": [
{
"name": "fwefwefwef",
"id": "262768",
"children": [
{
"name": "87ok78",
"id": "262765",
"children": [
{
"name": "78o78",
"id": 0,
"children": [
{
"name": "we4yhesrhy",
"id": "262764",
"children": [
{
"name": "test1",
"id": 0,
"children": [
{
"name": "",
"id": "262766",
"children": []
}
]
},
{
"name": "test2",
"id": 0,
"children": [
{
"name": "",
"id": "262766",
"children": []
}
]
}
]
}
]
},
{
"name": "7o78o76o8",
"id": 0,
"children": [
{
"name": "",
"id": "262766",
"children": []
}
]
},
{
"name": "ko",
"id": 0,
"children": [
{
"name": "",
"id": "262767",
"children": []
}
]
}
]
}
]
}
]
}
]
}
]
}
]
};
I need to create a function to search for all matching values for key "id" with given value.
So far I have created one recursive function:
function searchOccurances(theObject, value,path) {
var result = null;
if(theObject instanceof Array) {
for(var i = 0; i < theObject.length; i++) {
result = searchOccurances(theObject[i],value,path+","+i);
}
}
else
{
for(prop in theObject) {
if(prop == 'id') {
if(theObject[prop] == value) {
keyOccurances.push(path);
}
}
if((theObject[prop] instanceof Array) || (theObject[prop] instanceof Object))
{
if((theObject[prop].length!=undefined)&&(theObject[prop].length!=0))
{
result = searchOccurances(theObject[prop],value,path+","+prop);
}
}
}
}
return result;
}
keyOccurances=[];
searchOccurances(object,262762,'');
console.log(keyOccurances);
//Output
[",children,0,children,0", ",children,1,children,0", ",children,2,children,0"] -- correct
keyOccurances=[];
searchOccurances(object,262768,'');
console.log(keyOccurances);
//Output
[",children,1,children,0,children,1,children,0", ",children,1,children,0,children,2,children,0"] --wrong
The function returns array of comma separated paths of matched value but doesn't seems to be getting right results. For the first call with value '262762' gives corrects path list but for value '262768' gives incorrect path list.
Kindly help.
I'd suggest to provide a better test object. Would you really have so many children with 'id = 0' in a real use case? Would you have 2 children with the same ID at all? That makes things pretty hard to debug.
Below is an example function that should work as expected.
function search(object, value) {
var res = [], searchPath;
(searchPath = function(children, path) {
var n, newPath;
for(n in children) {
if(typeof children[n].id !== 'undefined' && parseInt(children[n].id, 10) === value) {
res.push(path);
}
newPath = path.slice();
newPath.push(children[n].id);
searchPath(children[n].children, newPath);
}
})([ object ], []);
return res;
}
console.log(search(object, 262762));
console.log(search(object, 262768));
Output:
[["262761", 0], ["262761", 0], ["262761", 0]]
[["262761", 0, "262762", 0], ["262761", 0, "262762", "262763"]]
The above code is not (yet) bullet-proof but hopefully is it short enough to be easily understandable.
If I understand your questions correctly, you're looking for all paths where a specific id is present. I'd recommend not reinventing the wheel here and using an existing library. We use object-scan for most of our data processing now. It's powerful once you wrap your head around it. Here is how you'd answer your question
// const objectScan = require('object-scan');
const findKeys = (haystack, id) => objectScan(['**'], {
joined: true,
filterFn: ({ value }) => value.id === id
})(haystack);
const object = { name: 'tfifkhul', id: '262761', children: [{ name: 'rthrth', id: 0, children: [{ name: 'test', id: '262762', children: [] }] }, { name: 'rthsrth', id: 0, children: [{ name: 'test', id: '262762', children: [] }] }, { name: 'rthrthhrth', id: 0, children: [{ name: 'test', id: '262762', children: [{ name: 'rtjrtj', id: 0, children: [{ name: 'fwefwefwef', id: '262768', children: [] }] }, { name: 'hsrtjrtdjrtj', id: 0, children: [{ name: 'we4yhesrhy', id: '262764', children: [] }] }, { name: 'lol', id: '262763', children: [{ name: 'fwefwefwef', id: '262768', children: [{ name: '87ok78', id: '262765', children: [{ name: '78o78', id: 0, children: [{ name: 'we4yhesrhy', id: '262764', children: [{ name: 'test1', id: 0, children: [{ name: '', id: '262766', children: [] }] }, { name: 'test2', id: 0, children: [{ name: '', id: '262766', children: [] }] }] }] }, { name: '7o78o76o8', id: 0, children: [{ name: '', id: '262766', children: [] }] }, { name: 'ko', id: 0, children: [{ name: '', id: '262767', children: [] }] }] }] }] }] }] }] };
console.log(findKeys(object, '262762'));
/* =>
[ 'children[2].children[0]',
'children[1].children[0]',
'children[0].children[0]' ]
*/
console.log(findKeys(object, '262768'));
/* =>
[ 'children[2].children[0].children[2].children[0]',
'children[2].children[0].children[0].children[0]' ]
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan
Edit: The accepted answer didn't make much sense to me (based on the question), but here is how you could generate the same output
// const objectScan = require('object-scan');
const findIdPath = (haystack, id) => objectScan(['**'], {
reverse: false,
filterFn: ({ value, parents, context }) => {
if (value.id === id) {
context.push(parents.filter((p) => 'id' in p).map((p) => p.id).reverse());
}
}
})(haystack, []);
const object = { name: 'tfifkhul', id: '262761', children: [{ name: 'rthrth', id: 0, children: [{ name: 'test', id: '262762', children: [] }] }, { name: 'rthsrth', id: 0, children: [{ name: 'test', id: '262762', children: [] }] }, { name: 'rthrthhrth', id: 0, children: [{ name: 'test', id: '262762', children: [{ name: 'rtjrtj', id: 0, children: [{ name: 'fwefwefwef', id: '262768', children: [] }] }, { name: 'hsrtjrtdjrtj', id: 0, children: [{ name: 'we4yhesrhy', id: '262764', children: [] }] }, { name: 'lol', id: '262763', children: [{ name: 'fwefwefwef', id: '262768', children: [{ name: '87ok78', id: '262765', children: [{ name: '78o78', id: 0, children: [{ name: 'we4yhesrhy', id: '262764', children: [{ name: 'test1', id: 0, children: [{ name: '', id: '262766', children: [] }] }, { name: 'test2', id: 0, children: [{ name: '', id: '262766', children: [] }] }] }] }, { name: '7o78o76o8', id: 0, children: [{ name: '', id: '262766', children: [] }] }, { name: 'ko', id: 0, children: [{ name: '', id: '262767', children: [] }] }] }] }] }] }] }] };
console.log(findIdPath(object, '262762'));
// => [ [ '262761', 0 ], [ '262761', 0 ], [ '262761', 0 ] ]
console.log(findIdPath(object, '262768'));
// => [ [ '262761', 0, '262762', 0 ], [ '262761', 0, '262762', '262763' ] ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.8.0"></script>
Disclaimer: I'm the author of object-scan