Reputation: 193
Trying to filter results dynamically in a function by building a querycontainer which is always null. I don't undestand why because when I debug, I see that q variable is filled within the function but when I check the value of it, it is always null. Example code is below. Do you have any idea what I do wrong?
Thank you.
QueryContainer q = null;
if (!ProductType.HasValue || (ProductType.HasValue && ProductType.Value == B2CVariables.PRODUCTTYPE_PRODUCT))
{
q = Query<ProductModel>.Term(t => t.Field(u => u.ProductTypeID == B2CVariables.PRODUCTTYPE_PRODUCT));
q &= Query<ProductModel>.Term(t => t.Field(u => u.Stocks.Any() ? u.Stocks.Any(z => z.StatusID == B2CVariables.STATUS_PRODUCT_ONLINE && (!z.CheckStockStatus || (z.CheckStockStatus && z.CurrentStockCount > 0))) : false));
}
Upvotes: 0
Views: 1460
Reputation: 125538
The construction of the query is not correct according to the signature of a Term
query constructed with the static Query<T>
type.
Field(Func<T, object>)
is a strongly typed expression to get the field that the query should operate on and the value with which the field must match for a term query should be specified using .Value(object value)
. Here's an examplem assuming the following setup
public static class B2CVariables
{
public const int PRODUCTTYPE_PRODUCT = 2;
public const int STATUS_PRODUCT_ONLINE = 1;
}
public class ProductModel
{
public IList<Stock> Stocks { get; set;}
public int ProductTypeID { get; set;}
}
public class Stock
{
public int StatusID { get; set;}
public bool CheckStockStatus { get; set;}
public int CurrentStockCount { get; set;}
}
The query
if (!ProductType.HasValue || (ProductType.HasValue && ProductType.Value == B2CVariables.PRODUCTTYPE_PRODUCT))
{
q = Query<ProductModel>.Term(t => t
.Field(u => u.ProductTypeID)
.Value(B2CVariables.PRODUCTTYPE_PRODUCT));
q &= Query<ProductModel>.Term(t => t
.Field(u => u.Stocks.First().StatusID)
.Value(B2CVariables.STATUS_PRODUCT_ONLINE)) &&
(Query<ProductModel>.Term(t => t
.Field(u => u.Stocks.First().CheckStockStatus)
.Value(false)) ||
(Query<ProductModel>.Term(t => t
.Field(u => u.Stocks.First().CheckStockStatus)
.Value(true)) &&
Query<ProductModel>.Range(t => t
.Field(u => u.Stocks.First().CurrentStockCount)
.GreaterThan(0))));
}
u.Stocks.First().StatusID
is an expression to get a status id of a child object on ProductModel
; the fact that we used .First()
doesn't mean that we are asking for the first status id, it's just an expression that determines how to access status id in a concise manner. See the section on field inference for more details.
Because Query<T>.Term(t => t.Field(u => u.Field).Value(value))
can get long winded when combining many queries, there is a shorthand Query<T>.Term(t => t.Field, value)
that can be used instead (it's shorter in practice, even if it looks almost the same in this example due to indentation!)
if (!ProductType.HasValue || (ProductType.HasValue && ProductType.Value == B2CVariables.PRODUCTTYPE_PRODUCT))
{
q = Query<ProductModel>.Term(
t => t.ProductTypeID,
B2CVariables.PRODUCTTYPE_PRODUCT);
q &= Query<ProductModel>.Term(
t => t.Stocks.First().StatusID,
B2CVariables.STATUS_PRODUCT_ONLINE) &&
(Query<ProductModel>.Term(
t => t.Stocks.First().CheckStockStatus,
false) ||
(Query<ProductModel>.Term(
t => t.Stocks.First().CheckStockStatus,
true) &&
Query<ProductModel>.Range(t => t
.Field(u => u.Stocks.First().CurrentStockCount)
.GreaterThan(0))));
}
Both produce the following query
{
"bool": {
"must": [
{
"term": {
"productTypeID": {
"value": 2
}
}
},
{
"term": {
"stocks.statusID": {
"value": 1
}
}
},
{
"bool": {
"should": [
{
"term": {
"stocks.checkStockStatus": {
"value": false
}
}
},
{
"bool": {
"must": [
{
"term": {
"stocks.checkStockStatus": {
"value": true
}
}
},
{
"range": {
"stocks.currentStockCount": {
"gt": 0.0
}
}
}
]
}
}
]
}
}
]
}
}
However, this query is probably not going to do what you want; Because there is a bool
query that combines two queries across a child object (a term
query on checkStockStatus
and a range
on currentStockcount
), the Stock
object should be modelled as a nested
object such that a match for both queries must be from the same stock object.
Once modeled as a nested object, the query would become
int? ProductType = 2;
QueryContainer q = null;
if (!ProductType.HasValue || (ProductType.HasValue && ProductType.Value == B2CVariables.PRODUCTTYPE_PRODUCT))
{
q = Query<ProductModel>.Term(t => t
.Field(u => u.ProductTypeID)
.Value(B2CVariables.PRODUCTTYPE_PRODUCT));
q &= Query<ProductModel>.Nested(n => n
.Path(u => u.Stocks.First())
.Query(nq => nq
.Term(t => t
.Field(u => u.Stocks.First().StatusID)
.Value(B2CVariables.STATUS_PRODUCT_ONLINE)) &&
(nq.Term(t => t
.Field(u => u.Stocks.First().CheckStockStatus)
.Value(false)) ||
(nq.Term(t => t
.Field(u => u.Stocks.First().CheckStockStatus)
.Value(true)
) && nq.Range(t => t
.Field(u => u.Stocks.First().CurrentStockCount)
.GreaterThan(0)
)))
)
);
}
with the query json
{
"bool": {
"must": [
{
"term": {
"productTypeID": {
"value": 2
}
}
},
{
"nested": {
"query": {
"bool": {
"must": [
{
"term": {
"stocks.statusID": {
"value": 1
}
}
},
{
"bool": {
"should": [
{
"term": {
"stocks.checkStockStatus": {
"value": false
}
}
},
{
"bool": {
"must": [
{
"term": {
"stocks.checkStockStatus": {
"value": true
}
}
},
{
"range": {
"stocks.currentStockCount": {
"gt": 0.0
}
}
}
]
}
}
]
}
}
]
}
},
"path": "stocks"
}
}
]
}
}
Upvotes: 1