2

I am having a hard time filtering through an array of objects based on a value in a nested array of objects. I have a chat application where a component renders a list of chats that a user has. I want to be able to filter through the chats by name when a user types into an input element.

Here is an example of the array or initial state :

const chats= [
  {
    id: "1",
    isGroupChat: true,
    users: [
      {
        id: "123",
        name: "Billy Bob",
        verified: false
      },
      {
        id: "456",
        name: "Superman",
        verified: true
      }
    ]
  },
  {
    id: "2",
    isGroupChat: true,
    users: [
      {
        id: "193",
        name: "Johhny Dang",
        verified: false
      },
      {
        id: "496",
        name: "Batman",
        verified: true
      }
    ]
  }
];

I want to be able to search by the Users names, and if the name exists in one of the objects (chats) have the whole object returned.

Here is what I have tried with no results

 const handleSearch = (e) => {

    const filtered = chats.map((chat) =>
      chat.users.filter((user) => user.name.includes(e.target.value))
    );
    console.log(filtered);
    // prints an empty array on every key press
  };
  const handleSearch = (e) => {
    const filtered = chats.filter((chat) =>
      chat.users.filter((user) => user.name.includes(e.target.value))
    );
    console.log(filtered);
   // prints both objects (chats) on every keypress
  };

Expected Results

  • If the input value is "bat" I would expect the chat with Id of 2 to be returned
[{
    id: "2",
    isGroupChat: true,
    users: [
      {
        id: "193",
        name: "Johhny Dang",
        verified: false
      },
      {
        id: "496",
        name: "Batman",
        verified: true
      }
    ]
  }]
  

4 Answers 4

2

The second approach seems a little closer to what you're trying to accomplish. There's two problems you may still need to tackle:

  1. Is the search within the name case insensitive? If not, you're not handling that.
  2. The function being used by a filter call needs to return a boolean value. Your outer filter is returning all results due to the inner filter returning the array itself and not a boolean expression. Javascript is converting it to a "truthy" result.

The following code should correct both of those issues:

const filtered = chats.filter((chat) => {
    const searchValue = e.target.value.toLowerCase();
    return chat.users.filter((user) => user.name.toLowerCase().includes(searchValue)).length > 0;
});

The toLowerCase() calls can be removed if you want case sensitivity. The .length > 0 verifies that the inner filter found at least one user with the substring and therefore returns the entire chat objects in the outer filter call.

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

Comments

1

If you want to get object id 2 when entering bat you should transform to lowercase

const handleSearch = (e) => 
 chats.filter(chat =>
   chat.users.filter(user => user.name.toLowerCase().includes(e.target.value)).length
);

try this it should work

Comments

0
const handleSearch2 = (e) => {

    const filtered = chats.filter((chat) =>
      chat.users.some((user) => user.name.includes(e))
    );
    console.log(filtered);
};

filter needs a predicate as argument, or, in other words, a function that returns a boolean; here some returns a boolean. Using map as first iteration is wrong because map creates an array with the same number of elements of the array that's been applied to.

Comments

0

Going the easy route, you can do this.

It will loop first over all the chats and then in every chat it will check to see if the one of the users' username contains the username passed to the function. If so, the chat will be added to the filtered list.

Note, I am using toLowerCase() in order to make the search non case sensitive, you can remove it to make it case sensitive.

const handleSearch = (username) => {
    var filtered = [];

    chats.forEach((chat) => {
        chat.users.forEach((user) => {
            if (user.name.toLowerCase().includes(username.toLowerCase())) {
                filtered.push(chat);
            }
        });
    });
    
    console.log(filtered);
    return filtered;
}

handleSearch('bat');

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.