Dawn17
Dawn17

Reputation: 8297

Filtering a JavaScript object with nested structure

let data = [
    {
        title: 'aa',
        releases: [
            { version: '1', owner: 'john'},
            { version: '2', owner: 'bob'}
        ]
    },
    {
        title: 'bb',
        releases: [
            { version: '1', owner: 'john'},
            { version: '2', owner: 'jack'}
        ]
    },
    {
        title: 'cc',
        releases: [
            { version: '1', owner: 'doo'},
            { version: '2', owner: 'park'}
        ]
    },
]

I have an array of objects that looks like above.

I am trying to filter the objects by the owner inside the releases array.

What I've tried is

data.filter(item => 
        ['john'].some(
            item.releases.some(
                obj=>obj.owner.toLowerCase().includes(['john'])
            )
        )
    )

I used an array of string(s) to have multiple search queries in the future. But this gives me an error

Uncaught TypeError: true is not a function

How can I solve this?

The result should be all objects that have john as an owner in any of its releases array

Upvotes: 1

Views: 171

Answers (4)

3limin4t0r
3limin4t0r

Reputation: 21130

If the intent is to check for a single name you can negate this answer. However if the intent of the question is to check for multiple names you can fix your code in the following way.

The issue is that you're providing a true/false value to the first some call, this should be a function.

const names = ['john'];
data.filter(item =>
  names.some(name => // added `name =>`
    item.releases.some(release =>
      release.owner.toLowerCase().includes(name) // changed `['john']` into `name`
    )
  )
);

However, you can also achieve the same functionality with less iterations by using an regex.

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
const escapeRegExp = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

const names = ['john'],
      pattern = names.map(escapeRegExp).join("|"),
      regex = new RegExp(pattern, "i"); // i = ignore case (removing the need of toLowerCase)

data.filter(item => item.releases.some(release => release.owner.match(regex)));

Upvotes: 0

Umer Farooqui
Umer Farooqui

Reputation: 307

You can try this:

let data = [
    {
        title: 'aa',
        releases: [
            { version: '1', owner: 'john'},
            { version: '2', owner: 'bob'}
        ]
    },
    {
        title: 'bb',
        releases: [
            { version: '1', owner: 'john'},
            { version: '2', owner: 'jack'}
        ]
    },
    {
        title: 'cc',
        releases: [
            { version: '1', owner: 'doo'},
            { version: '2', owner: 'park'}
        ]
    },
];

var result = data.filter(x => x.releases.some(rls => rls.owner.toLowerCase().includes(['john'])));

console.log(result);

Upvotes: 0

Alex Wayne
Alex Wayne

Reputation: 187034

That ['john'].some( call isn't really helping. You have the logic already without that.

You are getting that error because you are passing the result of some() (which returns a boolean) to some() (which expect a function).

Also, when asking if a string includes a string, you should pass in a string, not an array.

const filteredData = data.filter(item => 
    item.releases.some(
        obj => obj.owner.toLowerCase().includes('john')
    )
)

Upvotes: 2

Code Maniac
Code Maniac

Reputation: 37755

some expects a function not value, in the outer most some you're just passing the value you need to pass function instead

data.filter(item =>  
        ['john'].some( () =>      //  <--- function
            item.releases.some(
                obj=>obj.owner.toLowerCase().includes('john')
            )
        )
    )

Infact you don't need outer some

data.filter(item =>  
     item.releases.some(
       obj=>obj.owner.toLowerCase().includes('john')
    )
)

Upvotes: 0

Related Questions