danpaz / bodybuilder

An elasticsearch query body builder :muscle:

Home Page:http://bodybuilder.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nested Sub-query does not generate correct elastic search syntax.

vinay11283 opened this issue · comments

bodybuilder()
	.query('term', 'field', 'something')
       .andQuery('bool', (q) => {
     	return q.query('term', 'obj1.color', 'blue')
  	})
        .build()

generates bool.query which is not valid as per ES
[bool] query does not support [query]

{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "field": "something"
          }
        },
        {
          "bool": {
            "query": {
              "term": {
                "obj1.color": "blue"
              }
            }
          }
        }
      ]
    }
  }
}

This is just simplistic scneario, I genuinely have some subqueries wiith nested path's as well which does not work. I can come up with better example if this does not make sense.

Please advise if there is a workaround I can apply ?

@vinay11283 I'm not sure what you're trying to query for, but can't you just do

bodybuilder()
	.query('term', 'field', 'something')
        .query('term', 'obj1.color', 'blue')
        .build()

@danpaz Thanks for your response. Sorry, I should have come up with a better example. I thought I would reporduce with a simple example but that was not a good choice.

Scenario: transactionId OR (firstName AND lastName) where firstName and lastName are nested fields in path

Here is how I construct it.

bodybuilder()
        .orQuery('match', 'transactionid', '1234')
        .orQuery('bool', oq=>{
            oq.andQuery('nested', 'path','application.account.person', nq=>{
              nq.andQuery('term', 'firstName', 'John')
              nq.andQuery('term', 'lastName', 'Doe')
              return nq
            })
          return oq
		})
        .build()

output 

{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "transactionid": "1234"
          }
        },
        {
          "bool": {
            "query": {
              "nested": {
                "path": "application.account.person",
                "query": {
                  "bool": {
                    "must": [
                      {
                        "term": {
                          "firstName": "John"
                        }
                      },
                      {
                        "term": {
                          "lastName": "Doe"
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      ]
    }
  }
}

As you can see there is a bool>query 

Now as soon as I include another non-nested field, in the sub query it generates it fine.
transactionId OR (firstName AND lastName AND dateOfBirth ) where firstName and lastName are nested fields in path

bodybuilder()
        .orQuery('match', 'transactionid', '1234')
        .orQuery('bool', oq=>{
            oq.andQuery('nested', 'path','application.account.person', nq=>{
              nq.andQuery('term', 'firstName', 'John')
              nq.andQuery('term', 'lastName', 'Doe')
              return nq
            })
           oq.andQuery('term', 'dateOfBirth', '1900-01-01') 
          return oq
		})
        .build()

generates fine

{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "transactionid": "1234"
          }
        },
        {
          "bool": {
            "must": [
              {
                "nested": {
                  "path": "application.account.person",
                  "query": {
                    "bool": {
                      "must": [
                        {
                          "term": {
                            "firstName": "John"
                          }
                        },
                        {
                          "term": {
                            "lastName": "Doe"
                          }
                        }
                      ]
                    }
                  }
                }
              },
              {
                "term": {
                  "dateOfBirth": "1900-01-01"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

That's a known-issue. You can't have a single level nesting. If you think about it, it's redundant. It can be brought up a level.

This sounds like the issue that #144 is trying to fix – however we didn't merge that PR since it would be a breaking change.

Furthermore most use cases can use the alternative described in #142: You can use filter instead of query and it will work without issue.

@johannes-scharlach Using filter instead of query will work, but filter and query have a different behavior regarding scoring (https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-filter-context.html).