4

This is how my datas look like

{
  "name": "thename",
  "openingTimes": {
    "monday": [
      {
        "start": "10:00",
        "end": "14:00"
      },
      {
        "start": "19:00",
        "end": "02:30"
      }
    ]
  }
}

I want to query this document saying, opened on monday between 13:00 and 14:00.
I tried this filter but it doesn't return my document:

{
  "filter": {
    "range": {
      "openingTimes.monday.start": {
        "lte": "13:00"
      },
      "openingTimes.monday.end": {
        "gte": "14:00"
      }
    }
  }
}

If I simply say opened on monday at 13:00, it works:

{
  "filter": {
    "range": {
      "openingTimes.monday.start": {
        "lte": "13:00"
      }
    }
  }
}

Or even closing on monday from 14:00, works too:

{
  "filter": {
    "range": {
      "openingTimes.monday.start": {
        "gte": "14:00"
      }
    }
  }
}

but combining both of them doens't give me anything. How can I manage to create a filter meaning opened on monday between 13:00 and 14:00 ?

EDIT

This is how I mapped the openingTime field

{
  "properties": {
    "monday": {
      "type": "nested",
      "properties": {
        "start": {"type": "date","format": "hour_minute"},
        "end": {"type": "date","format": "hour_minute"}
      }
    }
  }
}

SOLUTION (@DanTuffery)

Based on @DanTuffery answer I changed my filter to his (which is working perfectly) and added the type definition of my openingTime attribute.

For the record I am using elasticsearch as my primary db through Ruby-on-Rails using the following gems:

gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
gem 'elasticsearch-persistence', git: 'git://github.com/elasticsearch/elasticsearch-rails.git', require: 'elasticsearch/persistence/model'

Here is how my openingTime attribute's mapping looks like:

attribute :openingTimes, Hash,    mapping: {
                                    type: :object,
                                    properties: {
                                      monday:     {
                                        type: :nested,
                                        properties: {
                                          start:{type: :date, format: 'hour_minute'},
                                          end:  {type: :date, format: 'hour_minute'}
                                        }
                                      },
                                      tuesday:     {
                                        type: :nested,
                                        properties: {
                                          start:{type: :date, format: 'hour_minute'},
                                          end:  {type: :date, format: 'hour_minute'}
                                        }
                                      },
                                      ...
                                      ...
                                    }
                                  }

And here is how I implemented his filter:

def self.openedBetween startTime, endTime, day
  self.search filter: {
                nested: {
                  path: "openingTimes.#{day}",
                  filter: {
                    bool: {
                      must: [
                        {range: {"openingTimes.#{day}.start"=> {lte: startTime}}},
                        {range: {"openingTimes.#{day}.end"  => {gte: endTime}}}
                      ]
                    }
                  }
                }
              }
end

1 Answer 1

6

First create your mapping with the openingTimes object at the top level.

/PUT http://localhost:9200/demo/test/_mapping
{
  "test": {
    "properties": {
      "openingTimes": {
        "type": "object",
        "properties": {
          "monday": {
            "type": "nested",
            "properties": {
              "start": {
                "type": "date",
                "format": "hour_minute"
              },
              "end": {
                "type": "date",
                "format": "hour_minute"
              }
            }
          }
        }
      }
    }
  }
}

Index your document

/POST http://localhost:9200/demo/test/1
{
  "name": "thename",
  "openingTimes": {
    "monday": [
      {
        "start": "10:00",
        "end": "14:00"
      },
      {
        "start": "19:00",
        "end": "02:30"
      }
    ]
  }
}

With a nested filter query you can search for the document with the start and end fields within boolean range queries:

/POST http://localhost:9200/demo/test/_search
{
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "nested": {
          "path": "openingTimes.monday",
          "filter": {
            "bool": {
              "must": [
                {
                  "range": {
                    "openingTimes.monday.start": {
                      "lte": "13:00"
                    }
                  }
                },
                {
                  "range": {
                    "openingTimes.monday.end": {
                      "gte": "14:00"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Your filter works perfectly, I would never have found it by myself. I added the changes I made to my code based on your answer in an edit.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.