8000 Add aggregation stage support by LoicAvelin · Pull Request #925 · mongomock/mongomock · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add aggregation stage support #925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
39 changes: 38 additions & 1 deletion mongomock/aggregate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,43 @@
]


def _handle_unset_stage(in_collection, database, options, user_vars=None):
"""
Removes specified fields (including nested fields via dot notation) from each document in a collection.
Accepts either a single field name (string) or a list of field names.
Safely handles missing paths and does not raise errors if a field is absent.
"""
# Make a shallow copy of each document to avoid mutating the input collection
out_collection = [dict(doc) for doc in in_collection]

# Normalize options to a list of field names to remove
if isinstance(options, str):
fields = [options]
elif isinstance(options, list):
fields = options
else:
# Raise an error if the options are not valid
raise OperationFailure('$unset options must be a string or list of strings')

Check warning on line 1683 in mongomock/aggregate.py

View check run for this annotation

Codecov / codecov/patch

mongomock/aggregate.py#L1683

Added line #L1683 was not covered by tests

# Iterate over each document in the output collection
for out_doc in out_collection:
# For each field to remove
for field in fields:
# Support nested fields using dot notation
parts = field.split('.')
sub_doc = out_doc
# Traverse to the parent of the field to remove
for subfield in parts[:-1]:
sub_doc = sub_doc.get(subfield, {})
# If the path does not exist or is not a dict, stop traversing
if not isinstance(sub_doc, dict):
break

Check warning on line 1697 in mongomock/aggregate.py

View check run for this annotation

Codecov / codecov/patch

mongomock/aggregate.py#L1697

Added line #L1697 was not covered by tests
else:
# Remove the field if it exists
sub_doc.pop(parts[-1], None)
return out_collection


_PIPELINE_HANDLERS = {
'$addFields': _handle_add_fields_stage,
'$bucket': _handle_bucket_stage,
Expand Down Expand Up @@ -1693,7 +1730,7 @@
'$skip': lambda c, d, o, v: c[o:],
'$sort': _handle_sort_stage,
'$sortByCount': None,
'$unset': None,
'$unset': _handle_unset_stage,
'$unwind': _handle_unwind_stage,
}

Expand Down
13 changes: 13 additions & 0 deletions tests/test__collection_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,8 @@ def test__update_pipeline(self):
{'_id': 2, 'a': 1, 'b': 2},
{'_id': 3, 'a': 1, 'b': 2},
{'_id': 4, 'a': 1, 'b': 2},
{'_id': 5, 'a': 1, 'b': 2, 'c': {'d': 3}}, # Added for $unset tests
{'_id': 6, 'a': 1, 'b': 2, 'c': {'d': 3}}
]
)
# TODO(guludo): add test cases for other stages when they become
Expand All @@ -939,6 +941,17 @@ def test__update_pipeline(self):
4,
[{'$replaceRoot': {'newRoot': {'_id': '$_id', 'x': {'$add': ['$a', '$b']}}}}],
{'_id': 4, 'x': 3},
),
# Test cases for $unset
(
5,
[{'$unset': 'b'}], # Single field removal
{'_id': 5, 'a': 1, 'c': {'d': 3}},
),
(
6,
[{'$unset': ['a', 'c.d']}], # Multiple fields and nested removal
{'_id': 5, 'b': 2, 'c': {}},
),
)
for doc_id, update, expected in data:
Expand Down
Loading
0