I am trying to use fluent LINQ in C# to query an Elasticsearch server using the .NET NEST library.
I want to build the LINQ statement based on the incoming search request. If the search request has price range, I want to add a range clause to the Elasticsearch request. Here is my code
var products = await client.SearchAsync<Product>(x =>
{
x = x.Query(q =>
{
if (request.IsAvailable.HasValue)
{
// this gets called, but it is never added to the final elasticsearch call.
q = q.Match(b => b.Field(bm => bm.IsAvailable).Query(request.IsAvailable.Value ? "true" : "false")) as QueryContainerDescriptor<Product>;
}
if (request.MinPrice.HasValue || request.MaxPrice.HasValue)
{
// this gets called, but it is never added to the final elasticsearch call.
q = q.Range(r =>
{
if (request.MinPrice.HasValue)
{
r = r.Field(x => x.Price).GreaterThanOrEquals(request.MinPrice.Value);
}
if (request.MaxPrice.HasValue)
{
r = r.Field(x => x.Price).LessThanOrEquals(request.MaxPrice.Value);
}
return r;
}) as QueryContainerDescriptor<Product>;
}
if (request.Types != null && request.Types.Length > 0)
{
// this gets called, but it is never added to the final elasticsearch call.
q = q.Terms(t => t.Field(f => f.Type).Terms(request.Types)) as QueryContainerDescriptor<Product>;
}
return q;
});
x = x.Source(s => s.Excludes(se =>
{
// This works! There fields are being excluded as expected
if (request.ExcludeSummary)
{
se = se.Field(sef => sef.Summary);
}
if (request.ExcludeTimestamp)
{
se = se.Field(sef => sef.Timestamp);
}
if (request.ExcludeLabels)
{
se = se.Field(sef => sef.Labels);
}
if (request.ExcludeTags)
{
se = se.Field(sef => sef.Tags);
}
return se;
}));
return x;
});
All of my conditions with in the Query()
does not get added to the elasticsearch request. Meaning the generated json request does not have clause for the price or IsAvaliable. I suspect casting is the culprit, but not sure how to fix it.
The Source()
is working as expected. It adds the correct fields to the excludes
list.
How can I correctly add query clause to the Query()
section?
I figured out the issue. It seems that NEST takes the last clause and ignores all the previous clause.
Here is what I have done to fix it
var products = await client.SearchAsync<Product>(x =>
{
x = x.Query(q =>
{
QueryContainer qc = q;
if (request.IsAvailable.HasValue)
{
qc = qc && +q.Match(b => b.Field(bm => bm.IsAvailable).Query(request.IsAvailable.Value ? "true" : "false"));
}
if (request.MinPrice.HasValue || request.MaxPrice.HasValue)
{
qc = qc && +q.Range(r =>
{
if (request.MinPrice.HasValue)
{
r = r.Field(x => x.Price).GreaterThanOrEquals(request.MinPrice.Value);
}
if (request.MaxPrice.HasValue)
{
r = r.Field(x => x.Price).LessThanOrEquals(request.MaxPrice.Value);
}
return r;
});
}
if (request.Types != null && request.Types.Length > 0)
{
qc = qc && +q.Terms(t => t.Field(f => f.Type).Terms(request.Types));
}
return qc;
});
x = x.Source(s => s.Excludes(se =>
{
if (request.ExcludeSummary)
{
se = se.Field(sef => sef.Summary);
}
if (request.ExcludeTimestamp)
{
se = se.Field(sef => sef.Timestamp);
}
if (request.ExcludeLabels)
{
se = se.Field(sef => sef.Labels);
}
if (request.ExcludeTags)
{
se = se.Field(sef => sef.Tags);
}
return se;
}));
return x;
});