mongoqueriesmanager 1.0.0
MongoDBQueriesManager
Convert query parameters from API urls to MongoDB queries !
This project was inspired by api-query-params (JS Library).
Features:
Powerful: Supports most of MongoDB operators (in,regexp, ...) and features (nested objects, type casting, projection, range filter...)
Agnostic: Works with any web frameworks (Flask, Sanic, AIOHTTP, Django ...) and/or MongoDB libraries (pymongo, motor, ...)
Simple: ~500 LOC, Python typing
Tested: 100% code coverage
Installation:
⚠️ In version 1.0.0 dateparser is an extra dependencies
pip install mongo-queries-manager
pip install mongo-queries-manager['dateparser']
# OR
pipenv install mongo-queries-manager
pipenv install mongo-queries-manager['dateparser']
# OR
poetry add mongo-queries-manager
poetry add mongo-queries-manager['dateparser']
Usages:
Api
mqm(string_query: str, blacklist: Optional[List[str]] = None, casters: Optional[Dict[str, Callable]] = None, populate: bool = False) -> Dict[str, Any]:
Description
Converts string_query into a MongoDB query dict.
Arguments
string_query: query string of the requested API URL (ie, frist_name=John&limit=10), Works with url encoded. [required]
casters: Custom caster dict, used to define custom type (ie, casters={'string': str} / price=string(5.5) -> {'price': '5'}) [optional]
blacklist: Custom blacklist word, used to ignore specific value from query (ie, blacklist=[where] / company=id,where=43.60,1.44, -> {'company': 'id'}) [optional]
populate: A boolean value, used to activate the population logic (add a population field into returned dict)
Returns
The resulting dictionary contains the following properties:
filter: Contains the query criteria.
projection: Contains the query projection
sort: Contains the sort criteria (cursor modifiers).
skip: Contains the skip criteria (cursor modifiers).
limit: Contains the limit criteria (cursor modifiers).
population: Contains the population criteria. (Only when populate arg is true. To use this population list, a manual implementation is required)
Exception
In case of error the following exception was raised:
MongoDBQueriesManagerBaseError: Base MongoDBQueriesManager errors.
SkipError: Raised when skip is negative / bad value.
LimitError: Raised when limit is negative / bad value.
ListOperatorError: Raised list operator was not possible.
FilterError: Raised when parse filter method fail to find a valid match.
TextOperatorError: Raised when parse text operator contain an empty string.
CustomCasterFail: Raised when a custom cast fail.
ProjectionError: Raised when projection json is invalid.
LogicalPopulationError: Raised when method fail to find logical population item.
LogicalSubPopulationError: Raised when method fail to find logical sub population item.
Examples:
Simple demo
from mongo_queries_manager import mqm
mongodb_query = mqm(string_query="status=sent&price>=5.6&active=true×tamp>"
"2016-01-01&author.firstName=/john/i&limit=100&skip=50&sort=-timestamp&fields=-_id,-created_at")
# {
# 'filter':
# {
# 'status': 'sent',
# 'price': {'$gte': 5.6},
# 'active': True,
# 'timestamp': {'$gt': datetime.datetime(2016, 1, 1, 0, 0)},
# 'author.firstName': re.compile('/john/i')
# },
# 'projection': {'_id': 0, 'created_at': 0},
# 'sort': [('timestamp', -1)],
# 'skip': 50,
# 'limit': 100
# }
Examples with PyMongo
from typing import Dict, Any
from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.database import Database
from mongo_queries_manager import mqm
client: MongoClient = MongoClient('localhost', 27017)
db: Database = client['test-database']
collection: Collection = db['test-collection']
mongodb_query: Dict[str, Any] = mqm(string_query="status=sent&toto=true×tamp>2016-01-01&"
"author.firstName=/john/i&limit=100&skip=50&sort=-timestamp")
result = collection.find(**mongodb_query)
Supported features
Filter operators:
MongoDB
URI
Example
Result
$eq
key=val
type=public
{'filter': {'type': 'public'}}
$gt
key>val
count>5
{'filter': {'count': {'$gt': 5}}}
$gte
key>=val
rating>=9.5
{'filter': {'rating': {'$gte': 9.5}}}
$lt
key<val
createdAt<2016-01-01
{'filter': {'createdAt': {'$lt': datetime.datetime(2016, 1, 1, 0, 0)}}}
$lte
key<=val
score<=-5
{'filter': {'score': {'$lte': -5}}}
$ne
key!=val
status!=success
{'filter': {'status': {'$ne': 'success'}}}
$in
key=val1,val2
country=GB,US
{'filter': {'country': {'$in': ['GB', 'US']}}}
$nin
key!=val1,val2
lang!=fr,en
{'filter': {'lang': {'$nin': ['fr', 'en']}}}
$exists
key
phone
{'filter': {'phone': {'$exists': True}}}
$exists
!key
!email
{'filter': {'email': {'$exists': False}}}
$regex
key=/value/<opts>
email=/@gmail\.com$/i
{'filter': {'email': re.compile('/@gmail.com$/i')}}
$regex
key!=/value/<opts>
phone!=/^06/
{'filter': {'phone': { '$not': re.compile('/^06/')}}}
$text
$text=val
$text=toto -java
{'filter': {'$text': { '$search': 'toto -java'}}}
$text
$text=val
$text="toto"
{'filter': {'$text': { '$search': '"toto"'}}}
Skip / Limit operators:
Default operator keys are skip and limit.
Used to limit the number of records returned by the query (pagination, result limitation, ...).
Support empty value (ie, ...&skip=&... / ...&limit=&... ).
from typing import Dict, Any
from mongo_queries_manager import mqm
mongodb_query: Dict[str, Any] = mqm(string_query="skip=50&limit=50")
# {
# 'filter': {},
# 'sort': None,
# 'projection': None,
# 'skip': 50,
# 'limit': 50
# }
mongodb_query: Dict[str, Any] = mqm(string_query="skip=&limit=")
# {
# 'filter': {},
# 'sort': None,
# 'projection': None,
# 'skip': 0,
# 'limit': 0
# }
Sort operator:
Used to sort returned records.
Default operator key is sort.
Support empty value (ie, ...&sort=&...).
Sort accepts a comma-separated list of fields.
Default behavior is to sort in ascending order.
Use - prefixes to sort in descending order, use + prefixes to sort in ascending order.
from typing import Dict, Any
from mongo_queries_manager import mqm
mongodb_query: Dict[str, Any] = mqm(string_query="sort=created_at,-_id,+price")
#{
# 'filter': {},
# 'sort': [('created_at', 1), ('_id', -1), ('price', 1)],
# 'projection': None,
# 'skip': 0,
# 'limit': 0
#}
Projection operator:
Useful to limit fields to return in each records.
It accepts a comma-separated list of fields. Default behavior is to specify fields to return. Use - prefixes to return all fields except some specific fields.
Due to a MongoDB limitation, you cannot combine inclusion and exclusion semantics in a single projection with the exception of the _id field.
It also accepts JSON string to use more powerful projection operators (,elemMatch or $slice)
from typing import Dict, Any
from mongo_queries_manager import mqm
mongodb_query: Dict[str, Any] = mqm(string_query="fields=-_id,-price")
#{
# 'filter': {},
# 'sort': None,
# 'projection': {'_id': 0, 'price': 0},
# 'skip': 0,
# 'limit': 0
#}
mongodb_query: Dict[str, Any] = mqm(string_query="fields=_id,price")
#{
# 'filter': {},
# 'sort': None,
# 'projection': {'_id': 1, 'price': 1},
# 'skip': 0,
# 'limit': 0
#}
mongodb_query: Dict[str, Any] = mqm(
string_query='fields={"games": {"$elemMatch":{"score": {"$gt": 5}}}},joined,lastLogin')
#{
# 'filter': {},
# 'sort': None,
# 'projection': {'games': {'$elemMatch': {'score': {'$gt': 5}}}, 'joined': 1, 'lastLogin': 1}},
# 'skip': 0,
# 'limit': 0
#}
Range filter:
Useful to filter fields to return in each records by range.
No error was handle by this library for range filter
from typing import Dict, Any
from mongo_queries_manager import mqm
query_result: Dict[str, Any] = mqm(string_query="price>5&price<5")
# {
# 'filter':
# {
# 'price': {'$gt': 5.0, '$lt': 5.0},
# },
# 'sort': None,
# 'projection': None,
# 'skip': 0,
# 'limit': 0
# }
Custom caster:
Used to define custom type
Optional parameter
from typing import Dict, Any, List
from mongo_queries_manager import mqm
def parse_custom_list(custom_list: str) -> List[str]:
return custom_list.split(';')
query_result: Dict[str, Any] = mqm(string_query="price=string(5)&name=John&in_stock=custom_list(1;2;3;4)&"
"in_stock_string=custom_list(string(1);string(2);string(3);string(4))",
casters={'string': str, 'custom_list': parse_custom_list})
#{
# 'filter':
# {
# 'price': '5',
# 'name': 'John',
# 'in_stock': {'$in': [1, 2, 3, 4]},
# 'in_stock_string': {'$in': ['1', '2', '3', '4']}
# },
# 'sort': None,
# 'projection': None,
# 'skip': 0,
# 'limit': 0
#}
Contribution
Install all development dependencies
# Initialize a new virtual environment
poetry shell
# Install dev dependencies
poetry install --with format,lint,type,tools,tests -E dateparser
# Run tests
nox
# Pre commit (format / lint / type before commit)
pre-commit install
pre-commit run --all-files
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.