Search code examples
nest

How to filter with a nested document based on multiple terms?


I am trying to replicate this DSL query in NEST. Basically a structured filter that will return all of the products that have the color red.

{
  "query": {
    "bool": {
      "filter": [
        {
          "nested": {
            "path": "keywordFacets",
            "query": {
              "bool": {
                "filter": [
                  { "term": { "keywordFacets.name": "color" } },
                  { "term": { "keywordFacets.value": "Red" } }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Here is the POCO with attribute mapping.

[ElasticsearchType]
public class Product
{
    [Keyword]
    public long ProductId { get; set; }

    [Nested]
    public List<KeywordFacet> KeywordFacets { get; set; }

    // other properties...
}

[ElasticsearchType]
public class KeywordFacet
{
    [Keyword]
    public string Name { get; set; }
    [Keyword]
    public string Value { get; set; }
}

I can't figure out how to get the two terms inside the nested filter array. This is my failed attempt so far:

var searchRequest = new SearchDescriptor<Product>()
    .Query(q => q
        .Bool(b => b
            .Filter(bf => bf
                .Nested(nq => nq
                    .Path(nqp => nqp.KeywordFacets)
                    .Query(qq => qq
                        .Bool(bb => bb
                            .Filter(ff => ff
                                .Term(t => t
                                    .Field(p => p.KeywordFacets.First().Name)
                                    .Value("color")
                                    .Field(p2 => p2.KeywordFacets.First().Value).Value("Red")))))))));

Here is some sample data that is returned when I run the DSL query in Postman:

{
    "productId": 183150,
    "keywordFacets": [
        {
            "name": "color",
            "value": "Red"
        },
        {
            "name": "color",
            "value": "Blue"
        },
        {
            "name": "color",
            "value": "Grey"
        }
    ]
}

Solution

  • Here's the proper syntax after fumbling around for a while.

    var searchRequest = new SearchDescriptor<Product>()
        .Query(q => q
            .Bool(b => b
                .Filter(bf => bf
                    .Nested(nq => nq
                        .Path(nqp => nqp.KeywordFacets)
                        .Query(qq => qq.Bool(bb => bb
                                         .Filter(ff => ff
                                             .Term(t => t
                                                 .Field(p => p.KeywordFacets[0].Name).Value("color"))))
                                     && qq.Bool(bb => bb
                                         .Filter(ff => ff
                                             .Term(t => t
                                                 .Field(p2 => p2.KeywordFacets[0].Value).Value("Red"))))
                        )
                    )
                )
            )
        );