diff --git a/doc/changelog.rst b/doc/changelog.rst index dcc4c881c..b50563bc4 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -143,6 +143,13 @@ Breaking Changes in 4.0 opposed to the previous syntax which was simply ``if collection:`` or ``if database:``. You must now explicitly compare with None. +- Empty projections (eg {} or []) for + :meth:`~pymongo.collection.Collection.find`, and + :meth:`~pymongo.collection.Collection.find_one` + are passed to the server as-is rather than the previous behavior which + substituted in a projection of ``{"_id": 1}``. This means that an empty + projection will now return the entire document, not just the ``"_id"`` field. + Notable improvements .................... diff --git a/doc/migrate-to-pymongo4.rst b/doc/migrate-to-pymongo4.rst index 2906919b2..0ac6d393d 100644 --- a/doc/migrate-to-pymongo4.rst +++ b/doc/migrate-to-pymongo4.rst @@ -637,6 +637,22 @@ Can be changed to this:: You must now explicitly compare with None. +Collection.find returns entire document with empty projection +............................................................. +Empty projections (eg {} or []) for +:meth:`~pymongo.collection.Collection.find`, and +:meth:`~pymongo.collection.Collection.find_one` +are passed to the server as-is rather than the previous behavior which +substituted in a projection of ``{"_id": 1}``. This means that an empty +projection will now return the entire document, not just the ``"_id"`` field. +To ensure that behavior remains consistent, code like this:: + + coll.find({}, projection={}) + +Can be changed to this:: + + coll.find({}, projection={"_id":1}) + SONManipulator is removed ------------------------- diff --git a/pymongo/collection.py b/pymongo/collection.py index 7e8e29908..8632204b8 100644 --- a/pymongo/collection.py +++ b/pymongo/collection.py @@ -1246,6 +1246,10 @@ class Collection(common.BaseObject): .. versionchanged:: 4.0 Removed the ``modifiers`` option. + Empty projections (eg {} or []) are passed to the server as-is, + rather than the previous behavior which substituted in a + projection of ``{"_id": 1}``. This means that an empty projection + will now return the entire document, not just the ``"_id"`` field. .. versionchanged:: 3.11 Added the ``allow_disk_use`` option. diff --git a/pymongo/cursor.py b/pymongo/cursor.py index 78dffc662..c38adaf37 100644 --- a/pymongo/cursor.py +++ b/pymongo/cursor.py @@ -195,8 +195,6 @@ class Cursor(object): allow_disk_use = validate_boolean("allow_disk_use", allow_disk_use) if projection is not None: - if not projection: - projection = {"_id": 1} projection = helpers._fields_list_to_dict(projection, "projection") self.__spec = spec diff --git a/test/test_collection.py b/test/test_collection.py index a7d56bf7b..e81776a6a 100644 --- a/test/test_collection.py +++ b/test/test_collection.py @@ -1707,7 +1707,10 @@ class TestCollection(IntegrationTest): self.assertTrue("hello" in db.test.find_one(projection=frozenset(["hello"]))) self.assertTrue("hello" not in db.test.find_one(projection=frozenset(["foo"]))) - self.assertEqual(["_id"], list(db.test.find_one(projection=[]))) + self.assertEqual(["_id"], list(db.test.find_one(projection={'_id': + True}))) + self.assertTrue("hello" in list(db.test.find_one(projection={}))) + self.assertTrue("hello" in list(db.test.find_one(projection=[]))) self.assertEqual(None, db.test.find_one({"hello": "foo"})) self.assertEqual(None, db.test.find_one(ObjectId()))