Easysearch - searching for multiple terms returns no results


#1

Hi all,

I’m using EasySearch and I’d like to return results for when the user types more than one search term into the search field. For example, for the collection below, if they type an author name and part of the article title (e.g. ‘joe smith tetris’), I’d like to show all articles in the Articles collection that are written by Joe Smith and have the word ‘tetris’ in their title.

Here’s how I’m indexing the collection:

ArticlesIndex = new EasySearch.Index({
  collection: Articles,
  fields: ['title', 'summary', 'author', 'text'],
  engine: new EasySearch.Minimongo()
});

and here’s how I’m parsing the results in a helper:

searchresults: function(){
	var searchterm = Session.get("searchtext");
	if (searchterm){
		let cursor = ArticlesIndex.search(searchterm);
		return cursor.fetch();
	}
}

This is all working fine if I have only one search term (e.g. ‘Joe Smith’ or ‘tetris’) but as soon as I try search across multiple fields, I get zero results.

Any ideas how to do this with EasySearch, or even with regular find()?

Thanks!


#2

I haven’t used EasySearch but it sounds like your query string is being checked as a whole against each field you’ve specified. So searching for “joe smith tetris” is being interpreted as:

{ 
  title: 'joe smith tetris', 
  summary: 'joe smith tetris', 
  author: 'joe smith tetris', 
  text: 'joe smith tetris' 
}

The EasySearch docs seem to confirm this in their Engines section.

You might have to re-visit your UI a bit, with a general search box for combined searches across each field, then maybe an advanced search for specific field searches. You could have a “title” search box, an “author” search box, etc., then switch the EasySearch mongo aggregation operator to $and to “and” the specific field searches.


#3

Thanks @hwillson. I’d really like to avoid the multiple search boxes. The mongo aggregation operator defaults to $or according to the docs you linked to, which should be what I need.

Do you know of a way to do this without EasySearch just by running a regular mongo query? Essentially I’m assuming it would be a find() query where each part of the search term was checked against each indexed field, but I’m struggling to imagine how to write this in a way that isn’t massively complex…


#4

Have you found any solution for this?

I’m having the exact same issue now and even posted a question on stack overflow (no answers, yet):

http://stackoverflow.com/questions/37394136/meteor-multiword-searching-with-single-multiple-fields-using-easy-search

Is it possible to do that in an easy way with the easysearch package (without any new package)?

Best,
Amir


#5

Hey Amir,

I haven’t found a solution. I feel like I’m missing something obvious - it should be reasonably simple to search multiple terms across multiple fields with a single query…


#6

Hi Aragorn, that’s a pity. Is nobody here to help that could be interested in this case, as well? Besides the Stack Overflow question, I also opened a issue at Github:

Please let me know, if you ever have found the solution. Will do the same :slight_smile:


#7

Also looking into options for this. out of the box it does seem to only search a string of keyword within each index field. Need a way to break the search term up into keywords (by spaces) and search that against the fields and return all possible unique instance.


#8

Hi,
I didn’t used easy search as well, but, if I understood well, to do the results you want personnally I do it from the code. I request a find all, and I parse it in js like that :

var arg1 = "joe smith";
var arg2 = "tetris";
myArticleCollection = new Mongo.Collection("default.article");
var results = [];
myCollection.find({}).forEach(function(record){
    var arg1Ok = false;
    var arg2Ok = false;
    $.each(record, function(index, value) {
        if(arg1Ok == false && value == arg1){
            arg1Ok == true;
        }
        if(arg2Ok == false && value == arg2){
            arg2Ok == true;
        }
        if(arg1Ok && arg2Ok){
            results.push(record);
            return false; // break
        }
    });
});

This is not very clean but It works for me ! I’m agree this is not a great solution when you have 50 fields in your collection… but for 2/3 it’s enough.
After some research, I didn’t try that, but it should works :

myCollection.find({
    $and : [
        {$or : [{title : arg1},
                {summary : arg1},
                {author : arg1},
                {text : arg1}]
        },
        {$or : [{title : arg2},
                {summary : arg2},
                {author : arg2},
                {text : arg2}]
        }
    ]
}

There is maybe a $forEachField style thing to avoir the big $or… but didn’t found it actually.