# Help constructing .NET NEST query

**URL:** <https://discuss.elastic.co/t/help-constructing-net-nest-query/152762>\
**Category:** Elasticsearch\
**Created:** [October 17, 2018, 6:24am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762 "2018-10-17T06:24:54Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![rpm1984](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rpm1984/32/36595_2.png) [@rpm1984](https://discuss.elastic.co/u/rpm1984)\
**Post date:** [October 17, 2018, 6:24am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/1 "2018-10-17T06:24:54Z")

</div>

Hi there,

I'm using the NEST .NET client (6.3.1), and trying to compose a search query that is based on a number of (optional) parameters.

Here's what i've got so far:

```
var searchResponse = await _client.SearchAsync<Listing>(s => s
                .Query(qq =>
                {
                    var filters = new List<QueryContainer>();

                    if (filter.CategoryType.HasValue)
                    {
                        filters.Add(qq.Term(p => p.CategoryType, filter.CategoryType.Value));
                    }

                    if (filter.StatusType.HasValue)
                    {
                        filters.Add(qq.Term(p => p.StatusType, filter.StatusType.Value));
                    }

                    if (!string.IsNullOrWhiteSpace(filter.Suburb))
                    {
                        filters.Add(qq.Term(p => p.Suburb, filter.Suburb));
                    }

                    return ?????; // what do i do her?
                })
            );

```

`filter` is an object with a bunch of nullable properties. So, whatever has a value i want to add as a match query.

So, to achieve that i'm trying to build up a list of `QueryContainer`'s (not sure that's the right way), but struggling to figure out how to return that as a list of AND predicates.

Any ideas?

Thanks

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [October 22, 2018, 2:41am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/2 "2018-10-22T02:41:43Z")

</div>

What you're essentially trying to do is combine multiple queries together, where each query would run in a filter clause. The `bool` query is a compound query that can be used for this purpose, and the queries can be added as `filter` clauses.

Take a look at the documentation on [writing `bool` queries with NEST](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/bool-queries.html), as NEST overloads operators for query types to allow them to be easily combined with `&&`, `||`, and to run in a filter context with `+` unary operator.

Another feature of NEST that helps out here is the notion of conditionless queries; if the input to a query is determined to be conditionless i.e. a `null` or `empty` string for example, then NEST will omit the query altogether from the request. This means that you don't need to check whether each `filter` property is `null` before adding to the set of filters, NEST will perform this filtering by default.

---

<div class="post-metadata">

**Author:** ![rpm1984](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rpm1984/32/36595_2.png) [@rpm1984](https://discuss.elastic.co/u/rpm1984)\
**Post date:** [October 22, 2018, 5:24am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/3 "2018-10-22T05:24:27Z")

</div>

Hey Russ, thanks for your reply.

Great tips. I _almost_ got it working. Here's my code:

```
var searchResponse = _client.Search<Listing>(s => s
                .Query(q => q
                    .Bool(b => b
                        .Must(
                            bs => bs.Terms(p => p.Field(f => f.ListingId)
                                .Terms(filter.ListingIds)),
                            bs => bs.Term(p => p.Category, filter.Category),
                            bs => bs.Term(p => p.Status, filter.Status),
                            bs => bs.Term(p => p.Suburb, filter.Suburb),
                            bs => bs.DateRange(p => p.Field(f => f.SoldOrLeasedOn)
                                .GreaterThanOrEquals(filter.SoldOrLeasedAfter)),
                            bs => bs.Range(p => p.Field(f => f.Price)
                                .GreaterThanOrEquals(filter.MinPrice)
                                .LessThanOrEquals(filter.MaxPrice)),
                            bs => bs.GeoBoundingBox(p => p.Field(f => f.LatLong)
                                .BoundingBox(filter.BoundingBox.TopLeft.Lat, filter.BoundingBox.TopLeft.Long,
                                            filter.BoundingBox.BottomRight.Lat, filter.BoundingBox.BottomRight.Long))
                        )
                    )
                )
            );

```

So it worked, with the exception of the .GeoBoundingBox part. `filter.BoundingBox` is a sub-class, so that falls over if it's null. So i'd need to check for the existence here. As soon as you introduce a conditional aspect here, can't use the Fluent DSL, right?

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [October 22, 2018, 5:46am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/4 "2018-10-22T05:46:29Z")

</div>

Please could you format your code, using `</>` icon as explained in [this guide](https://discuss.elastic.co/t/about-the-elasticsearch-category/21). It will make your post more readable!

You can also use markdown style like:

````
```
CODE
```

````

This is the icon to use if you are not using markdown format:

 ![image](https://us1.discourse-cdn.com/elastic/original/3X/7/e/7e6e239431ec2d71cbf1beef741f2e93e7cc762c.jpg)

---

<div class="post-metadata">

**Author:** ![rpm1984](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rpm1984/32/36595_2.png) [@rpm1984](https://discuss.elastic.co/u/rpm1984)\
**Post date:** [October 22, 2018, 6:02am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/5 "2018-10-22T06:02:46Z")

</div>

Sorry. 😊

Updated.

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [October 22, 2018, 6:26am UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/6 "2018-10-22T06:26:07Z")

</div>

You can convert the expression to a method group, and return `null` if the condition isn't met. For example,

```auto
var searchResponse = _client.Search<Listing>(s => s
                .Query(q => q
                    .Bool(b => b
                        .Must(
                            bs => bs.Terms(p => p.Field(f => f.ListingId)
                                .Terms(filter.ListingIds)),
                            bs => bs.Term(p => p.Category, filter.Category),
                            bs => bs.Term(p => p.Status, filter.Status),
                            bs => bs.Term(p => p.Suburb, filter.Suburb),
                            bs => bs.DateRange(p => p.Field(f => f.SoldOrLeasedOn)
                                .GreaterThanOrEquals(filter.SoldOrLeasedAfter)),
                            bs => bs.Range(p => p.Field(f => f.Price)
                                .GreaterThanOrEquals(filter.MinPrice)
                                .LessThanOrEquals(filter.MaxPrice)),
                            bs =>
                            {
                                // if bounding box is null, don't filter on it
                                if (filter.BoundingBox == null)
                                {
                                    return null;
                                }
                                
                                return bs.GeoBoundingBox(p => p
                                    .Field(f => f.LatLong)
                                    .BoundingBox(
                                        filter.BoundingBox.TopLeft.Lat, 
                                        filter.BoundingBox.TopLeft.Long,
                                        filter.BoundingBox.BottomRight.Lat, 
                                        filter.BoundingBox.BottomRight.Long)
                                    );
                            }
                    )
                )
            );

```

You can also refactor it out into a separate method that accepts a `QueryContainerDescriptor<Listing>` and returns a `QueryContainer`.

---

<div class="post-metadata">

**Author:** ![rpm1984](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/rpm1984/32/36595_2.png) [@rpm1984](https://discuss.elastic.co/u/rpm1984)\
**Post date:** [October 22, 2018, 10:24pm UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/7 "2018-10-22T22:24:39Z")

</div>

Ah perfect, of course! Thanks Russ 🙂

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [November 19, 2018, 10:36pm UTC](https://discuss.elastic.co/t/help-constructing-net-nest-query/152762/8 "2018-11-19T22:36:24Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
