Skip to content

Commit fe2b6c0

Browse files
committed
Implement optional count in Feature Providers
1 parent 734dabe commit fe2b6c0

19 files changed

Lines changed: 165 additions & 29 deletions

docs/source/configuration.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ default.
253253
include_extra_query_parameters: false # include extra query parameters that are not part of the collection properties (default: false)
254254
# editable transactions: DO NOT ACTIVATE unless you have setup access control beyond pygeoapi
255255
editable: true # optional: if backend is writable, default is false
256+
count: true # optional: perform a count query for collection queries, default is true
256257
# coordinate reference systems (CRS) section is optional
257258
# default CRSs are http://www.opengis.net/def/crs/OGC/1.3/CRS84 (coordinates without height)
258259
# and http://www.opengis.net/def/crs/OGC/1.3/CRS84h (coordinates with ellipsoidal height)

pygeoapi/provider/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __init__(self, provider_def):
6565
raise RuntimeError('name/type/data are required')
6666

6767
self.editable = provider_def.get('editable', False)
68+
self.count = provider_def.get('count', True)
6869
self.options = provider_def.get('options')
6970
self.id_field = provider_def.get('id_field')
7071
self.uri_field = provider_def.get('uri_field')

pygeoapi/provider/csv_.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ def _load(self, offset=0, limit=10, resulttype='results',
194194

195195
feature_collection['features'].append(feature)
196196

197-
feature_collection['numberMatched'] = \
198-
len(feature_collection['features'])
197+
if self.count:
198+
feature_collection['numberMatched'] = \
199+
len(feature_collection['features'])
199200

200201
if identifier is not None and not found:
201202
return None

pygeoapi/provider/esri.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,13 @@ def query(self, offset=0, limit=10, resulttype='results',
147147
fc = {
148148
'type': 'FeatureCollection',
149149
'features': [],
150-
'numberMatched': self._get_count(params)
151150
}
152151

152+
if self.count or resulttype == 'hits':
153+
matched = self._get_count(params)
154+
LOGGER.debug(f'Found {matched} result(s)')
155+
fc['numberMatched'] = matched
156+
153157
if resulttype == 'hits':
154158
return fc
155159

@@ -159,7 +163,7 @@ def query(self, offset=0, limit=10, resulttype='results',
159163
params['resultOffset'] = offset
160164
params['resultRecordCount'] = limit
161165

162-
hits_ = min(limit, fc['numberMatched'])
166+
hits_ = min(limit, matched) if self.count else limit
163167
fc['features'] = self._get_all(params, hits_)
164168

165169
fc['numberReturned'] = len(fc['features'])

pygeoapi/provider/geojson.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ def query(self, offset=0, limit=10, resulttype='results',
188188
properties=properties,
189189
select_properties=select_properties)
190190

191-
data['numberMatched'] = len(data['features'])
191+
if self.count or resulttype == 'hits':
192+
data['numberMatched'] = len(data['features'])
192193

193194
if resulttype == 'hits':
194195
data['features'] = []

pygeoapi/provider/mongo.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ def _get_feature_list(self, filterObj, sortList=[], skip=0, maxitems=1,
102102
if sortList:
103103
featurecursor = featurecursor.sort(sortList)
104104

105-
matchCount = self.featuredb[self.collection].count_documents(filterObj)
106105
featurecursor.skip(skip)
107106
featurecursor.limit(maxitems)
108107
featurelist = list(featurecursor)
@@ -111,7 +110,7 @@ def _get_feature_list(self, filterObj, sortList=[], skip=0, maxitems=1,
111110
if skip_geometry:
112111
item['geometry'] = None
113112

114-
return featurelist, matchCount
113+
return featurelist
115114

116115
@crs_transform
117116
def query(self, offset=0, limit=10, resulttype='results',
@@ -144,20 +143,28 @@ def query(self, offset=0, limit=10, resulttype='results',
144143
ASCENDING if (sort['order'] == '+') else DESCENDING)
145144
for sort in sortby]
146145

147-
featurelist, matchcount = self._get_feature_list(
148-
filterobj, sortList=sort_list, skip=offset, maxitems=limit,
149-
skip_geometry=skip_geometry)
150-
151-
if resulttype == 'hits':
152-
featurelist = []
153-
154146
feature_collection = {
155147
'type': 'FeatureCollection',
156-
'features': featurelist,
157-
'numberMatched': matchcount,
158-
'numberReturned': len(featurelist)
148+
'features': []
159149
}
160150

151+
if self.count or resulttype == 'hits':
152+
matched = self.featuredb[self.collection].count_documents(
153+
filterobj)
154+
LOGGER.debug(f'Found {matched} result(s)')
155+
feature_collection['numberMatched'] = matched
156+
157+
if resulttype == 'hits':
158+
return feature_collection
159+
160+
featurelist = self._get_feature_list(
161+
filterobj, sortList=sort_list, skip=offset, maxitems=limit,
162+
skip_geometry=skip_geometry
163+
)
164+
165+
feature_collection['features'] = featurelist
166+
feature_collection['numberReturned'] = len(featurelist)
167+
161168
return feature_collection
162169

163170
@crs_transform
@@ -168,8 +175,7 @@ def get(self, identifier, **kwargs):
168175
:param identifier: feature id
169176
:returns: dict of single GeoJSON feature
170177
"""
171-
featurelist, matchcount = self._get_feature_list(
172-
{'_id': ObjectId(identifier)})
178+
featurelist = self._get_feature_list({'_id': ObjectId(identifier)})
173179
if featurelist:
174180
return featurelist[0]
175181
else:

pygeoapi/provider/socrata.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,14 @@ def query(self, offset=0, limit=10, resulttype='results',
123123

124124
fc = {
125125
'type': 'FeatureCollection',
126-
'features': [],
127-
'numberMatched': self._get_count(params)
126+
'features': []
128127
}
129128

129+
if self.count or resulttype == 'hits':
130+
matched = self._get_count(params)
131+
LOGGER.debug(f'Found {matched} result(s)')
132+
fc['numberMatched'] = matched
133+
130134
if resulttype == 'hits':
131135
# Return hits
132136
LOGGER.debug('Returning hits')

pygeoapi/provider/sql.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,23 +212,23 @@ def query(
212212
.options(selected_properties)
213213
)
214214

215-
matched = results.count()
216-
217-
LOGGER.debug(f'Found {matched} result(s)')
218-
219215
LOGGER.debug('Preparing response')
220216
response = {
221217
'type': 'FeatureCollection',
222-
'features': [],
223-
'numberMatched': matched,
224-
'numberReturned': 0
218+
'features': []
225219
}
226220

221+
if self.count or resulttype == 'hits':
222+
matched = results.count()
223+
LOGGER.debug(f'Found {matched} result(s)')
224+
response['numberMatched'] = matched
225+
227226
if resulttype == 'hits' or not results:
228227
return response
229228

230229
crs_transform_out = get_transform_from_spec(crs_transform_spec)
231230

231+
response['numberReturned'] = 0
232232
for item in (
233233
results.order_by(*order_by_clauses).offset(offset).limit(limit)
234234
):

pygeoapi/provider/tinydb_.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,10 @@ def query(self, offset=0, limit=10, resulttype='results',
226226
else:
227227
results = self.db.all()
228228

229-
feature_collection['numberMatched'] = len(results)
229+
if self.count or resulttype == 'hits':
230+
matched = len(results)
231+
LOGGER.debug(f'Found {matched} result(s)')
232+
feature_collection['numberMatched'] = matched
230233

231234
if resulttype == 'hits':
232235
return feature_collection

pygeoapi/resources/schemas/config/pygeoapi-config-0.x.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,10 @@ properties:
513513
type: boolean
514514
description: whether the resource is editable
515515
default: false
516+
count:
517+
type: boolean
518+
description: whether to perform a count query for collection queries
519+
default: true
516520
table:
517521
type: string
518522
description: table name for RDBMS-based providers

0 commit comments

Comments
 (0)