diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index 649435fb..b919b4f7 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -24,12 +24,16 @@ get_one_document_1: |- 'fields': ['id', 'title', 'poster', 'release_date'] }) get_documents_1: |- - client.index('movies').get_documents({'limit':2, 'filter': 'genres=action'}) + client.index('movies').get_documents({ + 'limit':2, 'filter': 'genres=action', + 'sort': ['rating:desc', 'release_date:asc'] # list format + }) get_documents_post_1: |- client.index('books').get_documents({ 'limit':3, 'fields': ['title', 'genres', 'rating', 'language'], - 'filter': '(rating > 3 AND (genres=Adventure OR genres=Fiction)) AND language=English' + 'filter': '(rating > 3 AND (genres=Adventure OR genres=Fiction)) AND language=English', + 'sort': 'rating:desc, title:asc' # comma-separated string format }) add_or_replace_documents_1: |- client.index('movies').add_documents([{ diff --git a/meilisearch/index.py b/meilisearch/index.py index 0207f1d5..cfbff045 100644 --- a/meilisearch/index.py +++ b/meilisearch/index.py @@ -403,6 +403,7 @@ def get_documents( - offset - limit - results : list of Document instances containing the documents information + - sort: A list of attributes written as an array or as a comma-separated string Raises ------ @@ -411,6 +412,12 @@ def get_documents( """ if parameters is None: parameters = {} + + # convert comma-separated sort string to list + sort = parameters.get("sort") + if isinstance(sort, str): + parameters["sort"] = [s.strip() for s in sort.split(",") if s.strip()] + response = self.http.post( f"{self.config.paths.index}/{self.uid}/{self.config.paths.document}/fetch", body=parameters, diff --git a/tests/index/test_index_document_meilisearch.py b/tests/index/test_index_document_meilisearch.py index 7c7a4579..35bc5f33 100644 --- a/tests/index/test_index_document_meilisearch.py +++ b/tests/index/test_index_document_meilisearch.py @@ -245,6 +245,80 @@ def test_get_documents_offset_optional_params_list_of_fields(index_with_document assert response_offset_limit.results[0].genre == response.results[1].genre +def test_get_documents_sort_fields(index_with_documents): + """Tests getting documents sorted by fields.""" + index = index_with_documents() + + # Make fields sortable: include 'rating' and 'release_date' + sortable_attributes = ["rating", "release_date"] + task = index.update_sortable_attributes(sortable_attributes) + index.wait_for_task(task.task_uid) # wait until sortable attributes are set + + documents = [ + {"id": 1, "title": "Inception", "release_date": "2010-07-16", "rating": 8.8}, + {"id": 2, "title": "Interstellar", "release_date": "2014-11-07", "rating": 8.6}, + {"id": 3, "title": "Parasite", "release_date": "2019-05-30", "rating": 8.6}, + {"id": 4, "title": "The Matrix", "release_date": "1999-03-31", "rating": 8.7}, + {"id": 5, "title": "The Dark Knight", "release_date": "2008-07-18", "rating": 9.0}, + ] + + # Add documents + task = index.add_documents(documents) + index.wait_for_task(task.task_uid) + + params = { + "limit": 5, + "fields": ["id", "title", "release_date", "rating"], + "sort": ["rating:desc", "release_date:asc"], + } + response = index.get_documents(params) + + # prepare expected order + sorted_docs = sorted(documents, key=lambda d: (-d["rating"], d["release_date"])) + + for resp_doc, expected_doc in zip(response.results, sorted_docs): + assert resp_doc.id == expected_doc["id"] + assert resp_doc.rating == expected_doc["rating"] + assert resp_doc.release_date == expected_doc["release_date"] + + +@pytest.mark.parametrize( + "sort_param", + [ + ["rating:desc", "release_date:asc"], # list format + "rating:desc, release_date:asc", # comma-separated string + ], +) +def test_get_documents_sort_formats(index_with_documents, sort_param): + index = index_with_documents() + + # Make fields sortable + sortable_attributes = ["rating", "release_date"] + task = index.update_sortable_attributes(sortable_attributes) + index.wait_for_task(task.task_uid) + + documents = [ + {"id": 1, "title": "Inception", "release_date": "2010-07-16", "rating": 8.8}, + {"id": 2, "title": "Interstellar", "release_date": "2014-11-07", "rating": 8.6}, + {"id": 3, "title": "Parasite", "release_date": "2019-05-30", "rating": 8.6}, + {"id": 4, "title": "The Matrix", "release_date": "1999-03-31", "rating": 8.7}, + {"id": 5, "title": "The Dark Knight", "release_date": "2008-07-18", "rating": 9.0}, + ] + + task = index.add_documents(documents) + index.wait_for_task(task.task_uid) + + params = {"limit": 5, "fields": ["id", "title", "release_date", "rating"], "sort": sort_param} + response = index.get_documents(params) + + sorted_docs = sorted(documents, key=lambda d: (-d["rating"], d["release_date"])) + + for resp_doc, expected_doc in zip(response.results, sorted_docs): + assert resp_doc.id == expected_doc["id"] + assert resp_doc.rating == expected_doc["rating"] + assert resp_doc.release_date == expected_doc["release_date"] + + def test_get_documents_filter(index_with_documents): index = index_with_documents() response = index.update_filterable_attributes(["genre"])