inveniosoftware / invenio-records-rest

Invenio records REST API module.
https://invenio-records-rest.readthedocs.io
MIT License
4 stars 63 forks source link

Dynamic query in invenio #216

Closed PSvishnu93 closed 6 years ago

PSvishnu93 commented 6 years ago

I want to write a dynamic query which completely depends on the get request. Is there any method available for this?

lnielsen commented 6 years ago

What exactly do you have in mind with dynamic queries?

REST APIs generated by Records-REST already allows you to do advanced queries. If you have something more exotic in mind like geospatial queries there's various different was you can plug into records-rest inorder to customize the elasticsearch query being executed.

PSvishnu93 commented 6 years ago

By dynamic query what I mean is adding filters to the search queries on ElasticSearch dynamically. The filters can be any value depending on the request. Is there any API that will be useful for this purpose.

lnielsen commented 6 years ago

In essence, you can completely customize the query you send to elasticsearch by providing your custom search_factory.

However, you can plug also own filters, aggregations, sorting etc: http://invenio-records-rest.readthedocs.io/en/latest/usage.html#faceted-search

Example

  1. Implement a filter function
# values contain the list of values from the request (e.g. ?bounds=<value 1>&bounds=<value 2>
def geo_bounding_box_filter(values):
    values = values[0].split(',')
    # note here, you can e.g. access flask.request and have access to all the query parameters
    return Q('geo_bounding_box', {
        'location.point': {
            'top_right': {
                'lat': Decimal(values[3]),
                'lon': Decimal(values[2]),
            },
            'bottom_left': {
                'lat': Decimal(values[1]),
                'lon': Decimal(values[0]),
            }
        }
    })
  1. Plug the filter in your config
# config.py
RECORDS_REST_FACETS = dict(
    records=dict(
        filters={
            # bounds is the name of the query string parameter (e.g. /api/records?bounds=...)
            'bounds': geo_bounding_box_filter,
    )
)

Then you can do something like this:

/api/records?bounds=1.11,2.22,3.33,4.44

PSvishnu93 commented 6 years ago

Thank you for the above answer. My requirement is bit different and a sample request is given below. 127.0.0.1:5000/?q=jp&interval=1D&platform=style_pf&ldap_roles=all The number of attributes will be different from time to time.

lnielsen commented 6 years ago

In simple terms, your URL 127.0.0.1:5000/?q=jp&interval=1D&platform=style_pf&ldap_roles=all is translated into an Elasticsearch query.

Could you show me what Elasticsearch query you would like above URL to perform? Then I can better understand what you try to achieve.

E.g. interval, platform and ldap_roles to me just look like filters. If so, you can define them via the RECORDS_REST_FACETS - there are various different forms of filters (term filters, range filters, etc). Filters are only applied if they are present in the URL.

PSvishnu93 commented 6 years ago

Thank you for the suggestion. I am trying to build a new app using these concepts. Can you please share a sample app developed using invenio_records_rest. From the example given I am unable to understand the program flow.

lnielsen commented 6 years ago

There's a self-contained example app provided in the repository.

However, also do try to read through the documentation if you didn't already do so.