Reputation: 1256
I am trying to use NEST to create search query dynamically based on user's input.
I have a Filter class with user inputs:
Public class ProductFilter
{
public string Name { get; set; }
public DateTime? PublishDateFrom { get; set; }
}
But for the properties like Name and PublishDateFrom , they could be empty or null if a user doesn't specify.
So when doing search using NEST like the following code:
var response1 = await client.SearchAsync<ProjectDocument>(s => s
.Index(Indices.Parse("products"))
.From(0)
.Size(10000)
.Type("product")
.Query(q => q
.....
)
);
I want to cover the case when Name or PublishDateFrom is empty or null in one search all.
Right now if I use:
...
.Query(q => q
.Term(p => p.Name, filter.Name)
When filter.Name is empty or null, then the search result is empty. I want to something like: if the filter.Name is empty or null, the Term Query related to Name is not executed or included in the SearchAsync call. When both Name and PublishDateFrom are empty or null, then the query should be using .MatchAll().
I am trying to use Bool Query, but can't handle this case either.
Is there any good way to solve this problem?
Upvotes: 3
Views: 4741
Reputation: 125498
NEST already supports this with a concept of Conditionless queries. Examine the output in each of the following
var filter = new ProductFilter();
client.Search<ProjectDocument>(s => s
.Index("products")
.From(0)
.Size(10000)
.Query(q => +q
.Term(p => p.Name, filter.Name) && +q
.DateRange(d => d
.Field(f => f.PublishDateFrom)
.GreaterThan(filter.PublishDateFrom)
)
)
);
This query takes advantage of query operator overloading to more easily build a bool
query.
With both null
properties on the filter
instance, the search request is
POST http://localhost:9200/products/projectdocument/_search?pretty=true
{
"from": 0,
"size": 10000
}
No query
specified is the same as a match_all
query.
If we change filter
to
var filter = new ProductFilter
{
Name = "foo"
};
then we get the following request
POST http://localhost:9200/products/projectdocument/_search?pretty=true
{
"from": 0,
"size": 10000,
"query": {
"bool": {
"filter": [
{
"term": {
"name": {
"value": "foo"
}
}
}
]
}
}
}
And if we change filter
to
var filter = new ProductFilter
{
Name = "foo",
PublishDateFrom = DateTime.UtcNow.Date
};
We get
POST http://localhost:9200/products/projectdocument/_search?pretty=true
{
"from": 0,
"size": 10000,
"query": {
"bool": {
"filter": [
{
"term": {
"name": {
"value": "foo"
}
}
},
{
"range": {
"publishDateFrom": {
"gt": "2017-06-25T00:00:00Z"
}
}
}
]
}
}
}
Upvotes: 6