Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 141 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ Here's a code snippet that demonstrates how to use Aggify to construct a MongoDB
```python
from mongoengine import Document, fields


class AccountDocument(Document):
username = fields.StringField()
display_name = fields.StringField()
Expand All @@ -56,105 +55,164 @@ class AccountDocument(Document):
deleted_at = fields.LongField()
banned_at = fields.LongField()

class PostDocument(Document):
owner = fields.ReferenceField('AccountDocument', db_field='owner_id')
caption = fields.StringField()
location = fields.StringField()
comment_disabled = fields.BooleanField()
stat_disabled = fields.BooleanField()
hashtags = fields.ListField()
archived_at = fields.LongField()
deleted_at = fields.LongField()
class FollowAccountEdge(Document):
start = fields.ReferenceField("AccountDocument")
end = fields.ReferenceField("AccountDocument")
accepted = fields.BooleanField()
meta = {
"collection": "edge.follow.account",
}

class BlockEdge(Document):
start = fields.ObjectIdField()
end = fields.ObjectIdField()
meta = {
"collection": "edge.block",
}
```

Aggify query:

```python
from aggify import Aggify, Q, F

query = Aggify(PostDocument)

query.filter(deleted_at=None, caption__contains='Aggify').order_by('-_id').lookup(
AccountDocument, query=[
Q(_id__exact='owner') & Q(deleted_at=None),
Q(is_verified__exact=True)
], let=['owner'], as_name='owner'
).filter(owner__ne=[]).add_fields({
"aggify": "Aggify is lovely",
}
).project(caption=0).out("post").pipelines
from models import *
from aggify import Aggify, F, Q
from bson import ObjectId

aggify = Aggify(AccountDocument)

pipelines = list(
(
aggify.filter(
phone__in=[],
id__ne=ObjectId(),
disabled_at=None,
banned_at=None,
deleted_at=None,
network_id=ObjectId(),
)
.lookup(
FollowAccountEdge,
let=["id"],
query=[Q(start__exact=ObjectId()) & Q(end__exact="id")],
as_name="followed",
)
.lookup(
BlockEdge,
let=["id"],
as_name="blocked",
query=[
(Q(start__exact=ObjectId()) & Q(end__exact="id"))
| (Q(end__exact=ObjectId()) & Q(start__exact="id"))
],
)
.filter(followed=[], blocked=[])
.group("username")
.annotate(annotate_name="phone", accumulator="first", f=F("phone") + 10)
.redact(
value1="phone",
condition="==",
value2="132",
then_value="keep",
else_value="prune",
)
.project(username=0)[5:10]
.out(coll="account")
)
)
```

Mongoengine equivalent query:

```python
[
{
'$match': {
'caption': {
'$options': 'i',
'$regex': '.*Aggify.*'
},
'deleted_at': None
}
},
{
'$sort': {
'_id': -1
}
},
{
'$lookup': {
'as': 'owner',
'from': 'account',
'let': {
'owner': '$owner_id'
},
'pipeline': [
{
'$match': {
'$expr': {
'$and': [
{
'$eq': ['$_id', '$$owner']
},
{
'deleted_at': None
}
]
}
{
"$match": {
"phone": {"$in": []},
"_id": {"$ne": ObjectId("65486eae04cce43c5469e0f1")},
"disabled_at": None,
"banned_at": None,
"deleted_at": None,
"network_id": ObjectId("65486eae04cce43c5469e0f2"),
}
},
{
"$lookup": {
"from": "edge.follow.account",
"let": {"id": "$_id"},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{
"$eq": [
"$start",
ObjectId("65486eae04cce43c5469e0f3"),
]
},
{"$eq": ["$end", "$$id"]},
]
}
},
{
'$match': {
'$expr': {
'$eq': ['$is_verified', True]
}
}
}
],
"as": "followed",
}
},
{
"$lookup": {
"from": "edge.block",
"let": {"id": "$_id"},
"pipeline": [
{
"$match": {
"$expr": {
"$or": [
{
"$and": [
{
"$eq": [
"$start",
ObjectId("65486eae04cce43c5469e0f4"),
]
},
{"$eq": ["$end", "$$id"]},
]
},
{
"$and": [
{
"$eq": [
"$end",
ObjectId("65486eae04cce43c5469e0f5"),
]
},
{"$eq": ["$start", "$$id"]},
]
},
]
}
}
]
}
},
{
'$match': {
'owner': {'$ne': []}
}
},
{
'$addFields': {
'aggify': {
'$literal': 'Aggify is lovely'
}
],
"as": "blocked",
}
},
{"$match": {"followed": [], "blocked": []}},
{"$group": {"_id": "$username", "phone": {"$first": {"$add": ["$phone", 10]}}}},
{
"$redact": {
"$cond": {
"if": {"$eq": ["phone", "132"]},
"then": "$$KEEP",
"else": "$$PRUNE",
}
},
{
'$project': {
'caption': 0
}
},
{
'$out': 'post'
}
},
{"$project": {"username": 0}},
{"$skip": 5},
{"$limit": 5},
{"$out": "account"},
]
```

Expand Down
38 changes: 19 additions & 19 deletions aggify/aggify.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ def __to_aggregate(self, query: Dict[str, Any]) -> None:
or "document_type_obj"
not in join_field.__dict__ # Check whether this field is a join field or not.
or issubclass(
join_field.document_type, EmbeddedDocument # noqa
) # Check whether this field is embedded field or not
join_field.document_type, EmbeddedDocument # noqa
) # Check whether this field is embedded field or not
or len(split_query) == 1
or (len(split_query) == 2 and split_query[1] in Operators.ALL_OPERATORS)
):
Expand Down Expand Up @@ -555,23 +555,23 @@ def lookup(
foreign_field: Union[str, None] = None,
) -> "Aggify":
"""
Generates a MongoDB lookup pipeline stage.

Args:
from_collection (Document): The document representing the collection to perform the lookup on.
as_name (str): The name of the new field to create.
query (list[Q] | Union[Q, None], optional): List of desired queries with Q function or a single query.
let (Union[List[str], None], optional): The local field(s) to join on. If provided,
localField and foreignField are not used.
local_field (Union[str, None], optional): The local field to join on when `let` is not provided.
foreign_field (Union[str, None], optional): The foreign field to join on when `let` is not provided.
let (Union[List[str], None], optional): The local field(s) to join on. If provided,
localField and foreignField are not used.
local_field (Union[str, None], optional): The local field to join on when let not provided.
foreign_field (Union[str, None], optional): The foreign field to join on when let not provided.

Returns:
Aggify: An instance of the Aggify class representing a MongoDB lookup pipeline stage.
Generates a MongoDB lookup pipeline stage.

Args:
from_collection (Document): The document representing the collection to perform the lookup on.
as_name (str): The name of the new field to create.
query (list[Q] | Union[Q, None], optional): List of desired queries with Q function or a single query.
let (Union[List[str], None], optional): The local field(s) to join on. If provided,
localField and foreignField are not used.
local_field (Union[str, None], optional): The local field to join on when `let` is not provided.
foreign_field (Union[str, None], optional): The foreign field to join on when `let` is not provided.
let (Union[List[str], None], optional): The local field(s) to join on. If provided,
localField and foreignField are not used.
local_field (Union[str, None], optional): The local field to join on when let not provided.
foreign_field (Union[str, None], optional): The foreign field to join on when let not provided.

Returns:
Aggify: An instance of the Aggify class representing a MongoDB lookup pipeline stage.
"""

lookup_stages = []
Expand Down