Reputation: 141
Having quite a small experience with Mongo, please help... I have Employee collection (fields are: FirstName, LastName, Title, etc) in the Mondo DB, using C# MongoDB driver and using the collection as IQueryable so I can search for the data by using LINQ.
I need to perform a complex search in Mongo's Employee collection. For example, a user enters SearchText="John Doe CEO", code split this string into an array: ["John", "Doe", "CEO"]. The task is: if any field (FirstName OR LastName OR Title) contains any word from the array, the query should return it as a result.
AFAIR, this statement works fine when I query a simple List:
collection.AsQueryable().Where(e =>
allWordsArr.Any(_ => e.FirstName.ToLower().StartsWith(_.ToLower())) ||
allWordsArr.Any(_ => e.LastName.ToLower().StartsWith(_.ToLower())) ||
allWordsArr.Any(_ => e.Title.ToLower().StartsWith(_.ToLower())))
but when I run the query on the real Mongo DB it fails due to an unsupported operator string[].Any... So I can't pass the array from the C# code into the Mongo DB and then - perform LINQ/search operations, based on the elements of the array provided... It seems like I can't use an array of strings as initial expression (allWordsArr.Any(...))
How can I perform a search by using multiple fields and an array of words? I'd prefer to use collection.AsQueryable(..)+LINQ approach, but if it's not possible - any suggestion is welcome...
Thanks a lot!
Upvotes: 1
Views: 622
Reputation: 5669
don't think it's possible to do with linq/asqueryable. you can do it with find, like so:
var allWords = new[] { "CEO", "Doe", "John" };
var filters = allWords.Select(w =>
Builders<Employee>.Filter.Regex(e => e.Title, "/^" + w + "/i") |
Builders<Employee>.Filter.Regex(e => e.FirstName, "/^" + w + "/i") |
Builders<Employee>.Filter.Regex(e => e.LastName, "/^" + w + "/i"));
var combinedFilter = Builders<Employee>.Filter.Or(filters);
var result = await collection.Find(combinedFilter).ToListAsync();
here's an alternative:
var regex = "/^" + string.Join("|", allWords) + "/i";
var filter = Builders<Employee>.Filter.Regex(e => e.FirstName, regex) |
Builders<Employee>.Filter.Regex(e => e.LastName, regex) |
Builders<Employee>.Filter.Regex(e => e.Title, regex);
var result = await collection.Find(filter).ToListAsync();
Upvotes: 1