From fc13085f547655bb48df2255a5dc06e47584f1e7 Mon Sep 17 00:00:00 2001
From: Markus Scheidgen <markus.scheidgen@gmail.com>
Date: Mon, 10 Feb 2020 12:27:18 +0100
Subject: [PATCH] Exclude unnecessary fields from the search results.

---
 gui/src/components/api.js | 4 +++-
 nomad/app/api/repo.py     | 8 +++++++-
 nomad/search.py           | 5 +++++
 tests/app/test_api.py     | 8 ++++++++
 tests/test_search.py      | 8 ++++++++
 5 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/gui/src/components/api.js b/gui/src/components/api.js
index e6f45d1499..3d4019b54a 100644
--- a/gui/src/components/api.js
+++ b/gui/src/components/api.js
@@ -384,7 +384,9 @@ class Api {
   async search(search) {
     this.onStartLoading()
     return this.swagger()
-      .then(client => client.apis.repo.search(search))
+      .then(client => client.apis.repo.search({
+        exclude: ['atoms', 'only_atoms', 'files', 'quantities', 'optimade', 'labels', 'geometries'],
+        ...search}))
       .catch(handleApiError)
       .then(response => response.body)
       .finally(this.onFinishLoading)
diff --git a/nomad/app/api/repo.py b/nomad/app/api/repo.py
index e8a3ed4b77..04900ddd6c 100644
--- a/nomad/app/api/repo.py
+++ b/nomad/app/api/repo.py
@@ -84,6 +84,8 @@ _search_request_parser.add_argument(
         'Possible values are %s.' % ', '.join(datamodel.Domain.instance.metrics_names)))
 _search_request_parser.add_argument(
     'statistics', type=bool, help=('Return statistics.'))
+_search_request_parser.add_argument(
+    'exclude', type=str, action='split', help='Excludes the given keys in the returned data.')
 for group_name in search.groups:
     _search_request_parser.add_argument(
         group_name, type=bool, help=('Return %s group data.' % group_name))
@@ -150,8 +152,9 @@ class RepoCalcsResource(Resource):
         """
 
         try:
+            parsed_args = _search_request_parser.parse_args()
             args = {
-                key: value for key, value in _search_request_parser.parse_args().items()
+                key: value for key, value in parsed_args.items()
                 if value is not None}
 
             scroll = args.get('scroll', False)
@@ -202,6 +205,9 @@ class RepoCalcsResource(Resource):
         elif len(metrics) > 0:
             search_request.totals(metrics_to_use=metrics)
 
+        if 'exclude' in parsed_args:
+            search_request.exclude(*parsed_args['exclude'])
+
         try:
             if scroll:
                 results = search_request.execute_scrolled(scroll_id=scroll_id, size=per_page)
diff --git a/nomad/search.py b/nomad/search.py
index 859308bceb..f44a12d4db 100644
--- a/nomad/search.py
+++ b/nomad/search.py
@@ -543,6 +543,11 @@ class SearchRequest:
 
         return self
 
+    def exclude(self, *args):
+        """ Exclude certain elastic keys from the search results. """
+        self._search = self._search.source(excludes=args)
+        return self
+
     def execute(self):
         """
         Exectutes without returning actual results. Only makes sense if the request
diff --git a/tests/app/test_api.py b/tests/app/test_api.py
index 8da6e5e8fe..4ef6deb3ac 100644
--- a/tests/app/test_api.py
+++ b/tests/app/test_api.py
@@ -881,6 +881,14 @@ class TestRepo():
             assert len(statistics['system']) == 1
             assert value in statistics['system']
 
+    def test_search_exclude(self, api, example_elastic_calcs, no_warn):
+        rv = api.get('/repo/?exclude=atoms,only_atoms')
+        assert rv.status_code == 200
+        result = json.loads(rv.data)['results'][0]
+        assert 'atoms' not in result
+        assert 'only_atoms' not in result
+        assert 'basis_set' in result
+
     metrics_permutations = [[], search.metrics_names] + [[metric] for metric in search.metrics_names]
 
     def test_search_admin(self, api, example_elastic_calcs, no_warn, admin_user_auth):
diff --git a/tests/test_search.py b/tests/test_search.py
index c131e57a5e..e538e84cb3 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -137,6 +137,14 @@ def test_search_totals(elastic, example_search_data):
     assert 'quantities' not in results
 
 
+def test_search_excludes(elastic, example_search_data):
+    for item in SearchRequest().execute_paginated()['results']:
+        assert 'atoms' in item
+
+    for item in SearchRequest().exclude('atoms').execute_paginated()['results']:
+        assert 'atoms' not in item
+
+
 @pytest.mark.parametrize("order_by", [None, 'upload_id'])
 def test_search_quantity(
         elastic, normalized: parsing.LocalBackend, test_user: datamodel.User,
-- 
GitLab