From 112cc0dfa11d354323d06b2c54255d7804692530 Mon Sep 17 00:00:00 2001 From: Roman Right Date: Fri, 17 Dec 2021 18:00:32 +0100 Subject: [PATCH] Search by linked documents fields (#171) --- beanie/__init__.py | 2 +- beanie/odm/queries/find.py | 13 ++++++------- docs/changelog.md | 10 +++++++++- docs/tutorial/relations.md | 20 ++++++++++++++++++++ pyproject.toml | 2 +- tests/odm/test_relations.py | 16 ++++++++++++++-- tests/test_beanie.py | 2 +- 7 files changed, 52 insertions(+), 13 deletions(-) diff --git a/beanie/__init__.py b/beanie/__init__.py index b4fb3e19..486f96d2 100644 --- a/beanie/__init__.py +++ b/beanie/__init__.py @@ -19,7 +19,7 @@ from beanie.odm.utils.general import init_beanie from beanie.odm.documents import Document -__version__ = "1.8.7" +__version__ = "1.8.8" __all__ = [ # ODM "Document", diff --git a/beanie/odm/queries/find.py b/beanie/odm/queries/find.py index c7e4a1c8..78f66ac2 100644 --- a/beanie/odm/queries/find.py +++ b/beanie/odm/queries/find.py @@ -560,12 +560,9 @@ def _set_cache(self, data): @property def motor_cursor(self): if self.fetch_links: - aggregation_pipeline: List[Dict[str, Any]] = [ - {"$match": self.get_filter_query()} - ] - aggregation_pipeline += construct_lookup_queries( - self.document_model - ) + aggregation_pipeline: List[ + Dict[str, Any] + ] = construct_lookup_queries(self.document_model) sort_pipeline = { "$sort": {i[0]: i[1] for i in self.sort_expressions} } @@ -575,10 +572,12 @@ def motor_cursor(self): aggregation_pipeline.append({"$skip": self.skip_number}) if self.limit_number != 0: aggregation_pipeline.append({"$limit": self.limit_number}) + + aggregation_pipeline.append({"$match": self.get_filter_query()}) + aggregation_pipeline.append( {"$project": get_projection(self.projection_model)} ) - return self.document_model.get_motor_collection().aggregate( aggregation_pipeline, session=self.session ) diff --git a/docs/changelog.md b/docs/changelog.md index 8e270333..cccee69c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,12 @@ Beanie project changes +## [1.8.8] - 2021-12-17 + +### Added + +- Search by linked documents fields (for pre-fetching search only) + ## [1.8.7] - 2021-12-12 ### Fixed @@ -611,4 +617,6 @@ how specific type should be presented in the database [1.8.6]: https://pypi.org/project/beanie/1.8.6 -[1.8.7]: https://pypi.org/project/beanie/1.8.7 \ No newline at end of file +[1.8.7]: https://pypi.org/project/beanie/1.8.7 + +[1.8.8]: https://pypi.org/project/beanie/1.8.8 \ No newline at end of file diff --git a/docs/tutorial/relations.md b/docs/tutorial/relations.md index ab6fc514..3390c9dd 100644 --- a/docs/tutorial/relations.md +++ b/docs/tutorial/relations.md @@ -118,6 +118,26 @@ If a direct link is referred to a non-existent document, after the fetching it w Fetching will ignore non-existent documents for the list of links fields. +####Search by linked documents fields: + +If the `fetch_links` parameter is set to `True` searching by linked documents fields is available. + +By field of the direct link: +```python +houses = await House.find( + House.door.height == 2, + fetch_links=True +).to_list() +``` + +List of links: +```python +houses = await House.find( + House.windows.x > 10, + fetch_links=True +).to_list() +``` + ### On-demand fetch If you don't use prefetching, linked documents will be presented as objects of the `Link` class. You can fetch them manually then. diff --git a/pyproject.toml b/pyproject.toml index 21ad918b..7c2ccd9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "beanie" -version = "1.8.7" +version = "1.8.8" description = "Asynchronous Python ODM for MongoDB" authors = ["Roman "] license = "Apache-2.0" diff --git a/tests/odm/test_relations.py b/tests/odm/test_relations.py index a77bc8e2..81a1b3ca 100644 --- a/tests/odm/test_relations.py +++ b/tests/odm/test_relations.py @@ -32,8 +32,8 @@ async def houses(): for i in range(10): roof = Roof() if i % 2 == 0 else None house = await House( - door=Door(), - windows=[Window(x=10, y=10), Window(x=11, y=11)], + door=Door(t=i), + windows=[Window(x=10, y=10 + i), Window(x=11, y=11 + i)], roof=roof, name="test", height=i, @@ -88,6 +88,18 @@ async def test_prefetch_find_many(self, houses): await houses[0].fetch_link(House.door) assert isinstance(houses[0].door, Link) + houses = await House.find_many( + House.door.t > 5, fetch_links=True + ).to_list() + + assert len(houses) == 3 + + houses = await House.find_many( + House.windows.y == 15, fetch_links=True + ).to_list() + + assert len(houses) == 2 + async def test_prefetch_find_one(self, house): house = await House.find_one(House.name == "test") for window in house.windows: diff --git a/tests/test_beanie.py b/tests/test_beanie.py index 13870a7c..75dce47a 100644 --- a/tests/test_beanie.py +++ b/tests/test_beanie.py @@ -2,4 +2,4 @@ def test_version(): - assert __version__ == "1.8.7" + assert __version__ == "1.8.8"