0

I have an array of objects like this:

var data = [
   {id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
   {id:2,first_name:'Blaan',last_name:'Adey',age:35,birth:'2001-04-16'}
];

var searchColumn = ['first_name','last_name','birth'];

These values(searchColumn) ​​may change and not be constant. For this reason they must be read from the array

I want to do this now :

function searchData(Val){
    var newData = [];
    if (Val){
        for (let i=0 ; i < data.length ; i++){
            searchColumn.forEach(value => {
                 if (data[i][value].includes(Val)){
                     newData.push(data[i]);
                 }
            }
        }
    }
}

searchData('L');

please guide me.

Parviz
  • 21
  • 1
  • 7
  • You have to return `newData` at the end of `searchData` if you want to get its value. –  Nov 05 '20 at 23:19
  • Hello. I think this answer solve your problems, see: https://stackoverflow.com/questions/40603913/search-recursively-for-value-in-object-by-property-name – Cau Nov 05 '20 at 23:19
  • Your code will work fine if you correct the errors. As Matt pointed out, since you created `newData` within your function, you'll need to return it to use it. In addition to this, are missing a `)` that should close the `.forEach(`. Right after the second closing `}`. – Randy Casburn Nov 05 '20 at 23:23
  • you also return the entire data arrai-item ... `data[i]` ... and the same again and again for every item's property which contains the search value. But one only needs to return such an item once, as soon as [`some`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) search value does/did match. – Peter Seliger Nov 05 '20 at 23:32

2 Answers2

0

This should do.

You don't have to loop through the array, you can use build-in functions like map, some and filter to achieve this.

var data = [
   {id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
   {id:1,first_name:'John',last_name:'Bal',age:20,birth:'1992-01-12'},
   {id:2,first_name:'Blaan',last_name:'Adey',age:35,birth:'2001-04-16'}
];

var searchColumn = ['first_name','last_name','birth'];

var search = (searchParam) => {
    // map here applies the function  (value) => searchColumn.some(property => value[property] === searchParam) ? value : null
    // over every value in the array & some loops through every value in the search column
    // looking for an object where one of the properties specified in searchColumn has a value that matches our search parameter
    return data.map(value => searchColumn.some(property => value[property] === searchParam) ? value : null)
        .filter(result => !!result); // here we use filter to remove the null values mapped in the map function
}

search('John');
// result -> [{id:1,first_name:'John',last_name:'Doe',age:20,birth:'1992-01-12'},
//         -> {id:1,first_name:'John',last_name:'Bal',age:20,birth:'1992-01-12'}]

UPDATE: As suggested, an better solution:

var search = (searchParam) => {
    return data.filter(value => !!searchColumn.some(property => value[property] === searchParam));
}
Bargros
  • 521
  • 6
  • 18
  • 2
    You could `reduce()` instead of `map().filter()` and save yourself the second iteration. – pilchard Nov 05 '20 at 23:40
  • @pilchard yep good catch, I'm a little rusty with js lol. – Bargros Nov 05 '20 at 23:42
  • @pilchard ... more than a simple outer `filter` and an inner `some` is not needed. – Peter Seliger Nov 06 '20 at 00:59
  • @PeterSeliger The function `some` is needed for the solution to be flexible, basically doing it this way allows you to filter the array by however many properties you want without having to manually check that while filtering the array (as in `filter( v => v[p] === s || v[c] === r......)` ), best to define them somewhere and iterate over that array. – Bargros Nov 06 '20 at 17:37
  • @Bargros ... 1/2 ... why do you explain to me the obvious? I never stated something different. And I also was approaching just *pilchard* for making a remark at his comment. But of course, since we're in discussion now ... your approach can be improved to a simple `filter` function which features the `some` testing. There is no need for an additional `map` in first place. And this is exactly what I was already stating within my comment to *pilchard* ... – Peter Seliger Nov 06 '20 at 17:54
  • @Bargros ... 2/2 ... My approach does the same. It uses a `filter` function that incorporates an `include` but in addition a bound configuration too on top of an agnostic implementation in order to be reusable if it comes to changes of e.g. the OP's `searchColumn`s and *search parameter*s. – Peter Seliger Nov 06 '20 at 17:55
  • @PeterSeliger Since you're telling me I'm stating the obvious then I'll throw that back at you, pilchard already made what you're trying to point out very clear with his comment. – Bargros Nov 06 '20 at 17:58
  • @Bargros ... I really do not know what you try to prove nor what you really want to gain from a discussion with me. Two last sentences in order to answer the last comment of yours *"... , pilchard already made what you're trying to point out very clear with his comment."* ... (1) no, not really; *pilchard* was suggesting the combined usage of `reduce` and `some` which of course is not needed since the `filter`/`some` combination is the most natural approach to the OP's problem. (2) And the OP prefers `includes` for matching values, whereas your solution implements strict equality comparison. – Peter Seliger Nov 06 '20 at 18:25
0

... a configurable, thus more generic, approach based on Array.prototype.filter and Function.prototype.bind ...

function doesItemMatchBoundPropertyValueAndSearch(item) {
  const { keyList, search } = this;
  return keyList.some(key => item[key].includes(search));
}

const sampleDataList = [
  {id: 1, first_name: 'John', last_name: 'Doe', age: 20, birth: '1992-01-12'},
  {id: 2, first_name: 'Blaan', last_name: 'Adey', age: 35, birth: '2001-04-16'},
];
const searchColumn = ['first_name', 'last_name', 'birth'];

console.log(
  "search: 'L' :",
  sampleDataList.filter(
    doesItemMatchBoundPropertyValueAndSearch.bind({

      keyList: searchColumn,
      search: 'L',
    })
  )
);
console.log(
  "search: 'o' :",
  sampleDataList.filter(
    doesItemMatchBoundPropertyValueAndSearch.bind({

      keyList: searchColumn,
      search: 'o',
    })
  )
);
console.log(
  "search: 'n' :",
  sampleDataList.filter(
    doesItemMatchBoundPropertyValueAndSearch.bind({

      keyList: searchColumn,
      search: 'n',
    })
  )
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37