如何根据嵌套对象数组中的键过滤对象数组?

时间:2021-01-11 21:51:22

标签: javascript arrays reactjs

我很难根据嵌套对象数组中的值过滤对象数组。我有一个聊天应用程序,其中一个组件呈现用户拥有的聊天列表。我希望能够在用户输入输入元素时按名称过滤聊天记录。

这是数组或初始状态的示例:

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
      }
    ]
  }
];

我希望能够按用户名称进行搜索,如果名称存在于其中一个对象(聊天)中,则返回整个对象。

这是我尝试过但没有结果的方法

 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
  };

预期结果

  • 如果输入值为“bat”,我希望返回 Id 为 2 的聊天
[{
    id: "2",
    isGroupChat: true,
    users: [
      {
        id: "193",
        name: "Johhny Dang",
        verified: false
      },
      {
        id: "496",
        name: "Batman",
        verified: true
      }
    ]
  }]
  

4 个答案:

答案 0 :(得分:2)

第二种方法似乎更接近您要实现的目标。您可能仍需要解决两个问题:

  1. 名称中的搜索是否不区分大小写?如果没有,那你就没有处理。
  2. filter 调用使用的函数需要返回一个布尔值。由于内部 filter 返回数组本身而不是布尔表达式,因此您的外部 filter 正在返回所有结果。 Javascript 正在将其转换为“真实”结果。

以下代码应该纠正这两个问题:

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

如果您需要区分大小写,可以删除 toLowerCase() 调用。 .length > 0 验证内部过滤器至少找到了一个具有子字符串的用户,因此在外部过滤器调用中返回整个 chat 对象。

答案 1 :(得分:1)

如果你想在输入 bat 时得到对象 id 2 你应该转换成小写

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

试试这个应该可以的

答案 2 :(得分:0)

const handleSearch2 = (e) => {

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

filter 需要一个谓词作为参数,或者换句话说,一个返回布尔值的函数;这里 some 返回一个布尔值。 使用 map 作为第一次迭代是错误的,因为 map 创建了一个数组,该数组的元素数量与所应用的数组元素数量相同。

答案 3 :(得分:0)

走简单的路线,你可以做到这一点。

它将首先循环所有聊天,然后在每个聊天中检查用户的用户名是否包含传递给函数的用户名。如果是这样,聊天将被添加到过滤列表中。

注意,我使用 toLowerCase() 是为了使搜索不区分大小写,您可以将其删除以使其区分大小写。

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');
相关问题