gaxx
gaxx

Reputation: 63

How to create proper filters with Flask and PyMongo?

My first post here :)

I'm using Flask and PyMongo for my site and I want the user to have an ability to filter database results. To start simple:

Basic filter would return results based on the price argument. If the price is None then I want to return all the results.

From MongoDB docs:

The $or operator performs a logical OR operation on an array of two or more expressions and selects the documents that satisfy at least one of the expressions

   price = request.args.get('price')
   if price:
       price = int(price)

   posts = db.collection.find({ '$or' : [
                                {'price' : {'$lt' : price }},
                                {'price' : {'$ne' : None }}
                                ]
                              })

My idea was that if the price is not an integer (None) that the $or operator wouldn't satisfy first expression and move to the second one returning all that are not equal to None. However this doesn't really work and I can't figure any other way to display 'all' results when the argument is not passed or when it is wrong.

Also a bit borader questions - what if I want to have multiple filters? Should I create one big query for the database using $and operator and manipulate variable values in order to get the desired result? Or is there a better way? The only thing I thought about was a route for each filter but this doesn't sound like something that would work. Any suggestions are welcome! Thank you!

Upvotes: 1

Views: 2081

Answers (2)

edrtz
edrtz

Reputation: 21

If you want to pass an array from a front end (using query parameters) you can use the $in parameter for mongodb: URL Parameters sent in array as JSON object:

/read?job_type%5B%5D=Full%20Time&job_type%5B%5D=Part%20Time&country%5B%5D=Germany&country%5B%5D=China

@app.route("/read", methods=['GET', 'POST'])
def read():
    job_type = request.args.getlist('job_type[]')
    country = request.args.getlist('country[]')
    filter = {}
    if len(job_type) > 0: filter['job_type'] = {'$in': job_type}
    if len(country) > 0:  filter['country'] = {'$in': country}
    jobs = db_operations.find(filter)

Upvotes: 1

Belly Buster
Belly Buster

Reputation: 8814

EDIT:

For multiple filters:

filter = {}
if price is not None: filter['price'] = {'$lt' : price }
if quantity is not None: filter['quantity'] = {'$lt' : quantity }
if volume is not None: filter['volume'] = {'$lt' : volume }

posts = db.testcollection.find(filter)

ORIGNAL:

Try this to save yourself going slightly mad in the boolean logic world:

if price is None:
    filter = {}
else:
    filter = {'price' : {'$lt' : price }}

posts = db.collection.find(filter)

Upvotes: 1

Related Questions