Home > Mobile >  JS Filter array inside array by fields
JS Filter array inside array by fields

Time:01-09

Json structure:

[
    {
        "profile_id": 1,
        "nicknames": [
            {
                "nickname_id": 230,
                "nickname_value": "Rob",
                "admin_id": 5,
                "created_at": "2023-01-08T13:20:24.000000Z",
                "updated_at": "2023-01-08T13:20:24.000000Z"
            },
            {
                "nickname_id": 231,
                "nickname_value": "Wel",
                "admin_id": 5,
                "created_at": "2023-01-08T13:20:32.000000Z",
                "updated_at": "2023-01-08T13:20:32.000000Z"
            }
        ]
    },
    {
        "profile_id": 12,
        "nicknames": [
            {
                "nickname_id": 232,
                "nickname_value": "Pol",
                "admin_id": 5,
                "created_at": "2023-01-08T14:06:14.000000Z",
                "updated_at": "2023-01-08T14:06:14.000000Z"
            }
        ]
    }
]

I would like to have for example HTML input where I may provide some value. I need that script filter array by fields nickname_value, nickname_id, and profile_id from only one input field. I know how to filter inside an array but I don't have an idea to add a filter by profile_id.

CodePudding user response:

const data = [{
    "profile_id": 1,
    "nicknames": [{
        "nickname_id": 230,
        "nickname_value": "Rob",
        "admin_id": 5,
        "created_at": "2023-01-08T13:20:24.000000Z",
        "updated_at": "2023-01-08T13:20:24.000000Z"
      },
      {
        "nickname_id": 231,
        "nickname_value": "Wel",
        "admin_id": 5,
        "created_at": "2023-01-08T13:20:32.000000Z",
        "updated_at": "2023-01-08T13:20:32.000000Z"
      }
    ]
  },
  {
    "profile_id": 12,
    "nicknames": [{
      "nickname_id": 232,
      "nickname_value": "Pol",
      "admin_id": 5,
      "created_at": "2023-01-08T14:06:14.000000Z",
      "updated_at": "2023-01-08T14:06:14.000000Z"
    }]
  }
]

document.querySelector('input').addEventListener('input', ({
  target: {
    value
  }
}) => {
  const matches = data.filter(
    profile => profile.profile_id.toString() === value|| profile.nicknames.some(
      nickname => nickname.nickname_id.toString() === value || nickname.nickname_value === value
    )
  )
  document.querySelector('#results').innerHTML = matches.map(profile => profile.profile_id).join('')
})
<input>
<div id="results"></div>

CodePudding user response:

The problem gets simple if we can clearly state what we mean by a match, and the code gets simpler to write (and read) if we describe the predicates as functions.

Here's a proposal that says an object matches an input if the profile_id matches exactly or if any of its nicknames match. A nickname matches if the nickname_id matches exactly or if the input is a case-insensitive prefix of the nickname_value.

These criteria are a reasonable-seeming guess based on the prop names, but really up to the app.

// answer whether the object "matches" the input. presumes input is a string
function match(object, input) {
  if (object.profile_id ===  input) return true;

  const nicknameMatch = n => n.nickname_id ===  input ||
    n.nickname_value.toLowerCase().startsWith(input.toLowerCase());
  return object.nicknames.some(nicknameMatch)
}

With this, filter works straightforwardly...

const results = input.filter(object => match(object, input))

Once this is working, we might want to think about efficiency. One idea would be to cache a few things with the object, like stringified ids, and arrays of nickname ids and lowercase nickname values. If these objects are important to an app that's apt to grow, we could convert the literal objects to instances of a class, and give them a match method.

  • Related