1

I have an array of objects.

Within each object of the array, there can be multiple "Book" objects, all with dynamic keys. I want the objects with at least one "Book" object that is new.

For example:

const arr = [
  {
    id: '123',
    book1242: {isNew: true},
    book9023: {isNew: false},
  },
  {
    id: '123',
    book0374: {isNew: false},
    book9423: {isNew: false},
  },
  {
    id: '123',
    book8423: {isNew: false},
    book9023: {isNew: false},
  },
  {
    id: '123',
    book6534: {isNew: true},
    book9313: {isNew: false},
  },
]

So my filtered array will consist of the first and last element of the original array

Expected filtered array

const arr = [
  {
    id: '123',
    book1242: {isNew: true},
    book9023: {isNew: false},
  },
  {
    id: '123',
    book6534: {isNew: true},
    book9313: {isNew: false},
  },
]

I have tried using filter and map, but I get to the point where I have to loop through and check which book is new and I'm not sure how to return that object within the filter.

4 Answers 4

4

It sounds like you want something like this:

arr.filter((o) => Object.values(o).some((b) => b.isNew))

Will your array only ever have keys that are id and bookwxyz? If not you may need to do some checking on the values to make sure they aren't undefined

You could also explicitly check the key using Object.entries and a regular expression:

arr.filter((o) => Object.entries(o).some(([key, value]) => /book\d{4}/.test(key) && value.isNew))

Sign up to request clarification or add additional context in comments.

3 Comments

@RokoC.Buljan Good point, I was trying to find a way to deal with the fact that there might be other things in the array that could contain isNew but that's so unlikely I've changed the answer.
Beautifully simple. Terrific job!
PS, to provide more longevity, instead or relying to 4 - I would do /book\d+$/ so that in N years from now I don't need to care about bugs arising just because a library got more books.
2

You can use Array#some with Object.values.

const arr = [ { id: '123', book1242: {isNew: true}, book9023: {isNew: false}, }, { id: '123', book0374: {isNew: false}, book9423: {isNew: false}, }, { id: '123', book8423: {isNew: false}, book9023: {isNew: false}, }, { id: '123', book6534: {isNew: true}, book9313: {isNew: false}, }, ];
const res = arr.filter(obj=>Object.values(obj).some(({isNew})=>isNew));
console.log(res);

3 Comments

It won't work whenever there is any non-object values, like primitive boolean or float.
@w35l3y Have you tried it? It does work fine. In fact, the id is a primitive in the example.
You are right. It won't work with null or undefined only.
1

const arr=[{id:"123",book1242:{isNew:!0},book9023:{isNew:!1}},{id:"123",book0374:{isNew:!1},book9423:{isNew:!1}},{id:"123",book8423:{isNew:!1},book9023:{isNew:!1}},{id:"123",book6534:{isNew:!0},book9313:{isNew:!1}}];

const res = arr.filter(obj => {
  for(const [key, val] of Object.entries(obj)){
    if(key.substring(0,4) === 'book' && val.isNew === true){
      return obj
    }
   }
})

console.log(res)

1 Comment

This is certainly the most explicit and safe one, actually checking the key has book at the front. You could replace the for loop with some, and filter only requires you to return a boolean so you could just return key.substring(0,4) === 'book' && val.isNew directly
0
 let sorted =[]
  arr.forEach((el, i) => {
         let obj_values = Object.values(el);
         obj_values = obj_values.filter((elem) => typeof elem == 'object' && elem.isNew == true);
if(obj_values.length) sorted.push(arr[i])
     })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.