bkleeman
bkleeman

Reputation: 119

How do I retrieve records in MongoDB with PyMongo based on Flask URL variables?

Problem Statement

I am building an API that must retrieve documents from a mongodb database, and I need to define a route in the Flask app that allows me to use the Flask URL variable as a value in my mdb query.

I have tried the following:

@app.route("/infrastructure/<infrastructure_type>")
def get_infrastructure(infrastructure_type):
    infrastructure = db.infrastructure.find(jsonify(f'properties.type.primary: {infrastructure_type}'), projection = {"_id": False})
    return jsonify([resource for resource in infrastructure])

Expected results

I was expecting to be able to go to a route like http://127.0.0.1:5000/infrastructure/mine and see all of the documents whose primary type in the database is mine returned as JSON.

Actual results

I received a 500 Internal Server Error and the following error message:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.9/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/ben/Desktop/repos/rdcep/shotgun-api/app.py", line 23, in get_infrastructure
    infrastructure = db.infrastructure.find(jsonify(f'properties.type.primary: {infrastructure_type}'), projection = {"_id": False})
  File "/usr/local/lib/python3.9/site-packages/pymongo/collection.py", line 1523, in find
    return Cursor(self, *args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/pymongo/cursor.py", line 144, in __init__
    validate_is_mapping("filter", spec)
  File "/usr/local/lib/python3.9/site-packages/pymongo/common.py", line 494, in validate_is_mapping
    raise TypeError("%s must be an instance of dict, bson.son.SON, or "
TypeError: filter must be an instance of dict, bson.son.SON, or any other type that inherits from collections.Mapping

Example data from Mongo, showing the way the properties are nested

Example data from Mongo

Question

What do I need to do in order to get my query filter in a format that mongo will accept?

Upvotes: 0

Views: 1170

Answers (2)

bkleeman
bkleeman

Reputation: 119

As mentioned by Alexandre Mahdhaoui in this answer, I needed to pass a dict as my filter argument, but for some reason my database required dot notation for access. This answer contains the complete solution:

@app.route("/infrastructure/<infrastructure_type>")
def get_infrastructure(infrastructure_type):
    infrastructure = db.infrastructure.find({'properties.type.primary': infrastructure_type}, projection = {"_id": False})
    return jsonify([resource for resource in infrastructure])

Upvotes: 1

Alexandre Mahdhaoui
Alexandre Mahdhaoui

Reputation: 841

I suggest you directly pass a dict as your filter argument instead of jsonify(f'properties.type.primary: {infrastructure_type}')

Example:

@app.route("/infrastructure/<infrastructure_type>")
def get_infrastructure(infrastructure_type):
    infrastructure = db.infrastructure.find({'properties': {'type': {'primary': infrastructure_type}}}, projection = {"_id": False})
    return jsonify([resource for resource in infrastructure])

Upvotes: 1

Related Questions