Search code examples
javascriptjqueryarrayssearchlodash

how to case insentive contain search with lodash


I have a valid json file (i put only a limited part of that). i want to search incasesensitive and look as contain (suppose there is a record of Red Carpet in json file , if user search "red" it will show the matches's video_url (video_url of "Red Carpet). I have a limitation that i can't use ES6 because of hardware. please show how do i need to convert following json file to javascript object and use jquery or javascript to make a contain incasesensitive search. I can add lodash or any other javascript library to my project for this purpose.

[{
        "video_url": "http://63.237.48.3/ipnx/media/movies/Zane_Ziadi_HQ.mp4",
        "title": "Zane Ziadi"
    },
    {
        "video_url": "http://63.237.48.3/ipnx/media/movies/DarBastAzadiHQ.mp4",
        "title": "Darbast Azadi"
    },
    {
        "video_url": "http://63.237.48.3/ipnx/media/movies/Cheghadr_Vaght_Dari_HQ.mp4",
        "title": "Cheghadr Vaght Dari"
    },
    {
        "video_url": "http://63.237.48.3/ipnx/media/movies/Mashaal_HQ.mp4",
        "title": "Mashaal"
    },
    {
        "video_url": "http://63.237.48.3/ipnx/media/movies/Red_Carpet_HQ.mp4",
        "title": "Red Carpet"
    }
]

following code doesn't work :

  document.getElementById('input').addEventListener('change', function() {

 var name = document.getElementById('input').value.toLowerCase();
    var result = _.find(movies, {'title': name});
    if (!result){
       console.log('Nothing found');
    }else{
         console.log('Go to ' + result.video_url);

    }
    });

Edit2: update2

fixed and solved by Akrion comment, thanks so much to him

Edit3: update3

it seemed by Akrion answer, when search a for character "a" it would not return all title which has A as character , please modify and correct the code i try to run ES5 part answer and it only return zane ziadi the first item but not "Cheghadr Vaght Dari"

Edit4: update4 as Akrion suggested in his comment i can use filter instead of find to match all searches. i mark his answer for this thread forever


Solution

  • The issue with your code is that you are asking lodash to compare the exact contents of title and more importantly compare it while being case sensitive, since {title: name} triggers property match in lodash which simply compares the contents of title with the contents of the variable.

    You can create a search function via lodash methods and no ES6 like this:

    const data = [{ "video_url": "http://63.237.48.3/ipnx/media/movies/Zane_Ziadi_HQ.mp4", "title": "Zane Ziadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/DarBastAzadiHQ.mp4", "title": "Darbast Azadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Cheghadr_Vaght_Dari_HQ.mp4", "title": "Cheghadr Vaght Dari" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Mashaal_HQ.mp4", "title": "Mashaal" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Red_Carpet_HQ.mp4", "title": "Red Carpet" } ]
    
    const search = function(data, term) {
      return _.find(data, function(x) { 
        return _.includes(_.toLower(x.title), _.toLower(term))}) 
      }
    
    console.log(search(data, 'azadi'))
    console.log(search(data, 'Red'))
    console.log(search(data, 'zan'))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

    Using find, includes and toLower lodash methods.

    Your code then would look like:

    function search(data, term) {
      return _.find(data, function(x) { 
        return _.includes(_.toLower(x.title), _.toLower(term))}) 
    }
    
    document.getElementById('input').addEventListener('change', function() {
      var name = document.getElementById('input').value;
      var result = search(movies, name);  // <-- change to use the new search fn
      if (result) {
        console.log('Nothing found');
      } else {
        console.log('Go to ' + result.video_url);
      }
    });
    

    With ES5 you can also do this via:

    const data = [{ "video_url": "http://63.237.48.3/ipnx/media/movies/Zane_Ziadi_HQ.mp4", "title": "Zane Ziadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/DarBastAzadiHQ.mp4", "title": "Darbast Azadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Cheghadr_Vaght_Dari_HQ.mp4", "title": "Cheghadr Vaght Dari" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Mashaal_HQ.mp4", "title": "Mashaal" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Red_Carpet_HQ.mp4", "title": "Red Carpet" } ]
    
    const search = function(data, term) {
      return data.find(function(x) {
        return x.title.toLowerCase().indexOf(term.toLowerCase()) >= 0 })
    } 
    
    console.log(search(data, 'azadi'))
    console.log(search(data, 'Red'))
    console.log(search(data, 'zan'))

    With ES6 this would simply be:

    const data = [{ "video_url": "http://63.237.48.3/ipnx/media/movies/Zane_Ziadi_HQ.mp4", "title": "Zane Ziadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/DarBastAzadiHQ.mp4", "title": "Darbast Azadi" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Cheghadr_Vaght_Dari_HQ.mp4", "title": "Cheghadr Vaght Dari" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Mashaal_HQ.mp4", "title": "Mashaal" }, { "video_url": "http://63.237.48.3/ipnx/media/movies/Red_Carpet_HQ.mp4", "title": "Red Carpet" } ]
    
    const search = (data, term) => 
      data.find(({title}) => title.toLowerCase().includes(term.toLowerCase()))
    
    console.log(search(data, 'azadi'))
    console.log(search(data, 'Red'))
    console.log(search(data, 'zan'))

    Please note that this is not a super performant approach and if you are going to search hundreds/thousands of documents this way it will not perform well. You would need to look into other ways (Binary search etc) to solve this.