-
Notifications
You must be signed in to change notification settings - Fork 351
Make find(projection=...) return copies of the values #753
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
Make find(projection=...) return copies of the values #753
Conversation
Codecov Report
@@ Coverage Diff @@
## develop #753 +/- ##
===========================================
+ Coverage 95.08% 95.14% +0.06%
===========================================
Files 19 19
Lines 3743 3731 -12
===========================================
- Hits 3559 3550 -9
+ Misses 184 181 -3
Continue to review full report at Codecov.
|
|
I'm not sure if this needs a test to compare it against the real MongoDB engine or not. But I'll add one if you would like it. |
pcorpet
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR. I don't think we need a test in test__mongomock for this one, so let's keep it like this.
mongomock/collection.py
Outdated
| else: | ||
| doc_copy = _project_by_spec( | ||
| doc, _combine_projection_spec(fields), | ||
| self._copy_field(doc, container), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does the job but in many cases some values will be copied several times. I suggest that you update the _combine_projection_spec instead and add a copy in the places where the are no copies yet (doc_copy[key] = doc[key] and doc_copy[key] = val)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah… I think I see what you mean – if fields are excluded (e.g.find_one(projection={'field': 0})) or nested fields are used (e.g. find_one(projection={'field.subfield': 1})), then _project_by_spec would copy the values a second time.
I'll update the pull request accordingly, but I'm wondering a bit about the container parameter. As far as I can tell it's never anything but dict, so I'm wondering what its purpose is and if it would be OK to just copy.deepcopy() the values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The container parameter was meant to use the implementation of the codec option document_class, if it's not too much trouble I'd like to keep it as such for now.
Make sure that the values returned from find() and find_one() when a projection is specified don't share any references to the actual db documents. Fixes mongomock#728
Copy only included fields, and only do it once.
fad56a5 to
87671fd
Compare
mongomock/collection.py
Outdated
| elif isinstance(val, dict): | ||
| doc_copy[key] = _project_by_spec(val, spec, is_include, container) | ||
| elif (is_include and spec is not NOTHING) or (not is_include and spec is NOTHING): | ||
| doc_copy[key] = copy.deepcopy(val) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add at least a comment that this should use container if it's a dict-like object or may contain dict-like objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed it to use _copy_field instead now.
|
Thanks or the change |
Make sure that the values returned from find() and find_one() when a
projection is specified don't share any references to the actual db
documents.
Fixes #728