Engo
Engo

Reputation: 969

How to filter JSON data based on multiple criteria in JavaScript?

I am trying to filter out all records that don't contain values from the 5 arrays: ssn, spn, smft, ssl, svtv. The output is not correct because it only works in cases where the lists contain 1 element. The output array becomes empty when they contain multiple elements. I am trying to get records that don't contain one of the values from each list (OR). I think it doesn't work because it checks if each record doesn't contain all values in each list (AND). Any idea how to fix this?

jsonData

[{"sn": "234234234", "pn": "1014143", "mft": "hello world", "sl": "GG07", "vtv": "Yes"},{"sn": "324234234", "pn": "101423131143", "mft": "hello world 1", "sl": "GG08", "vtv": "Yes"}]

query

ssn: ['T234834U', 'T23423423'],
spn: ['1014114', '21412342'],
smft: ['Sbasdfa', 'asdfaser'],
ssl: ['BB03', 'SFD04'],
svtv: ['Yes']

Code

function getFiltered() {    
    var query = {
        sn: ssn, 
        pn: spn,
        mft: smft,
        sl: ssl,
        vtv: svtv
    }    
    var filtered = find_in_object(jsonData, query)
}

function find_in_object(my_object, my_criteria) {
    return my_object.filter(function(obj) {
        return Object.keys(my_criteria).every(function(c) {
            return JSON.stringify(obj[c]).indexOf(my_criteria[c]) === -1
        })
    })
}

Upvotes: 1

Views: 9478

Answers (3)

Oskar
Oskar

Reputation: 2607

You can use every for AND and some for OR. In your case you want to go thru the list of keys (so every for AND) and then check if the value exists in the search array. indexOf should do the job:

let jsonData = [
  {"sn": "234234234", "pn": "1014143", "mft": "hello world", "sl": "GG07", "vtv": "Yes"},
  {"sn": "324234234", "pn": "101423131143", "mft": "hello world 1", "sl": "GG08", "vtv": "Yes"}
]
  
let query = {
  mft: [],
  sl: ["GG08"],
  vtv: ["No"]
}
console.log(find_in_object(jsonData, query)); //returns one

let query2 = {
  sn: ['T234834U', 'T23423423'],
  pn: ['1014114', '21412342'],
  mft: ['Sbasdfa', 'asdfaser'],
  sl: ['BB03', 'SFD04'],
  vtv: ['Yes']
}
console.log(find_in_object(jsonData, query2)); //returns none

function find_in_object(my_array, my_criteria) {
  return my_array.filter(function(obj) {
    return Object.keys(my_criteria).every(function(key) {
      return (Array.isArray(my_criteria[key]) &&
        (my_criteria[key].some(function(criteria) {
          return (typeof obj[key] === 'string' && obj[key].indexOf(criteria) === -1)
        })) || my_criteria[key].length === 0);
    });
  });
}

Edited to cover some edge cases.

Upvotes: 2

James Hay
James Hay

Reputation: 7325

Something like this should work

function find_in_object(data, query) {
  return data.filter(function(record) { 
    for(var i in record) {
      if(query[i] && query[i].indexOf(record[i]) !== -1) {
        return false;
      }
    }
    return true;
  });
}

However it is not clear whether you want to match a complete key and value pair, or just a single value regardless of it's key. The above will only work if the key AND the value match.

Upvotes: 0

Stavros Angelis
Stavros Angelis

Reputation: 962

I would turn the json object in an array and then make a simple string comparison to each key.

$(document).ready(function() {
    var data = [{"mft": "hello world", "pn": "1014143", "vtv": "Yes", "pn": "T1323F2342", "sl": "GG07"},{"mft": "hello 1", "pn": "234234", "vtv": "Yes", "pn": "T252345234", "sl": "SDF87"}];


    filterData(data[0]);
});


function filterData(data) {
    var newArray = [];
     for (var key in data) {
        var value   = data[key];
        console.log(key, value);

        if (key==="ssn" || key==="spn" || key==="smft"|| key==="ssl"|| key==="svtv") {
            var object  = {key:value};
            newArray.push(object)
        }
    }
    return newArray;
}

Upvotes: 0

Related Questions