Skip to content

Commit df878e7

Browse files
Merge pull request #202 from sat-utils/develop
Release 0.3.0
2 parents 7477bc1 + 06220cc commit df878e7

21 files changed

+181
-61
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
5353
docker_build_and_test:
5454
machine:
55-
docker_layer_caching: true
55+
docker_layer_caching: false
5656
steps:
5757
- *restore_repo
5858
- checkout
@@ -68,7 +68,7 @@ jobs:
6868
6969
docker_deploy_production:
7070
machine:
71-
docker_layer_caching: true
71+
docker_layer_caching: false
7272
steps:
7373
- *restore_repo
7474
- run:
@@ -86,7 +86,7 @@ jobs:
8686
8787
docker_deploy_develop:
8888
machine:
89-
docker_layer_caching: true
89+
docker_layer_caching: false
9090
steps:
9191
- *restore_repo
9292
- run:

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,36 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased]
8+
9+
## [v0.3.0] - 2019-10-16
10+
11+
### Added
12+
- /stac/search linked to from /stac
13+
- New `ids` parameter added for searching by IDs
14+
- New `collections` parameter added for searching list of specific collections
15+
- SATAPI_COLLECTION_LIMIT environment variable added for the number of collections to return at the /stac and /collections endpoints. Since pagination is not supported at these endpoints this should be set higher than the number of collections available. Defaults to 100.
16+
17+
### Changed
18+
- Fields parameter changed to search on any fields rather than just fields under `properties`. Field under `properties` must now be referenced by `properties.<fieldname>`
19+
- `collection` now a top level field rather than a property
20+
21+
722
## [v0.2.6] - 2019-08-28
823

924
### Added
1025
- Support for `in` operator on property fields
26+
- SATAPI_COLLECTION_LIMIT environment variable added for the number of collections to return at the /stac and /collections endpoints. Since pagination is not supported at these endpoints this should be set higher than the number of collections available. Defaults to 100.
27+
28+
### Added
29+
- /stac/search linked to from /stac
30+
- New `ids` parameter added for searching by IDs
31+
- New `collections` parameter added for searching list of specific collections
32+
33+
### Changed
34+
- Fields parameter changed to search on any fields rather than just fields under `properties`. `property` fields must now be referenced by `property.fieldname`
35+
- `collection` now a top level field rather than a property
36+
1137

1238
## [v0.2.5] - 2019-06-21
1339

@@ -108,6 +134,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
108134
- Refactor and improve splitting
109135

110136
[Unreleased]: https://github.com/sat-utils/sat-api/compare/master...develop
137+
[v0.3.0]: https://github.com/sat-utils/sat-api/compare/v0.2.6...v0.3.0
138+
[v0.2.6]: https://github.com/sat-utils/sat-api/compare/v0.2.5...v0.2.6
111139
[v0.2.5]: https://github.com/sat-utils/sat-api/compare/v0.2.4...v0.2.5
112140
[v0.2.4]: https://github.com/sat-utils/sat-api/compare/v0.2.3...v0.2.4
113141
[v0.2.3]: https://github.com/sat-utils/sat-api/compare/v0.2.2...v0.2.3

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@ The STAC version supported by a given version of sat-api is shown in the table b
1212
| -------- | ---- |
1313
| 0.1.0 | 0.5.x |
1414
| 0.2.x | 0.6.x |
15+
| 0.3.x | 0.7.x |
16+
17+
## Usage
18+
19+
This repository contains just the Node libraries for running the API. The [sat-api-deployment](https://github.com/sat-utils/sat-api-deployment) repository is for deploying sat-api to AWS.
20+
21+
### Environment variables
22+
23+
There are some environment variables used in the code. Some do not have defaults and must be set.
24+
25+
| Name | Description | Default Value |
26+
| ---- | ----------- | ------------- |
27+
| STAC_ID | ID of this catalog | - |
28+
| STAC_TITLE | Title of this catalog | - |
29+
| STAC_DESCRIPTION | Description of this catalog | - |
30+
| STAC_DOCS_URL | URL to documentation | - |
31+
| SATAPI_URL | The root endpoint of this API to use for links | Inferred from request |
32+
| ES_BATCH_SIZE | Number of records to ingest in single batch | 500 |
33+
| SATAPI_ES_PRECISION | Precision to use for geometry queries, see [ES documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html) | '5mi' |
34+
| LOG_LEVEL | Level for logging | 'info' |
1535

1636

1737
## Development

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"lerna": "2.11.0",
3-
"version": "0.2.6",
3+
"version": "0.3.0",
44
"npmClient": "yarn",
55
"packages": [
66
"packages/*"

packages/api-lib/libs/api.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,19 @@ const extractFields = function (params) {
9292
return fieldRules
9393
}
9494

95+
const extractIds = function (params) {
96+
let idsRules
97+
const { ids } = params
98+
if (ids) {
99+
if (typeof ids === 'string') {
100+
idsRules = JSON.parse(ids)
101+
} else {
102+
idsRules = ids.slice()
103+
}
104+
}
105+
return idsRules
106+
}
107+
95108
const parsePath = function (path) {
96109
const searchFilters = {
97110
stac: false,
@@ -150,8 +163,10 @@ const addCollectionLinks = function (results, endpoint) {
150163
// Impure - mutates results
151164
const addItemLinks = function (results, endpoint) {
152165
results.forEach((result) => {
153-
const { id, links } = result
154-
const { collection } = result.properties
166+
let { links } = result
167+
const { id, collection } = result
168+
169+
links = (links === undefined) ? [] : links
155170
// self link
156171
links.splice(0, 0, {
157172
rel: 'self',
@@ -220,6 +235,10 @@ const collectionsToCatalogLinks = function (results, endpoint) {
220235
rel: 'self',
221236
href: `${endpoint}/stac`
222237
})
238+
catalog.links.push({
239+
rel: 'search',
240+
href: `${endpoint}/stac/search`
241+
})
223242
return catalog
224243
}
225244

@@ -302,14 +321,17 @@ const search = async function (
302321
const intersects = hasIntersects || bbox
303322
const query = extractStacQuery(queryParameters)
304323
const fields = extractFields(queryParameters)
324+
const ids = extractIds(queryParameters)
305325
const parameters = {
306326
datetime,
307327
intersects,
308328
query,
309329
sort,
310-
fields
330+
fields,
331+
ids
311332
}
312-
// Keep only exisiting parameters
333+
const colLimit = process.env.SATAPI_COLLECTION_LIMIT || 100
334+
// Keep only existing parameters
313335
const searchParameters = Object.keys(parameters)
314336
.filter((key) => parameters[key])
315337
.reduce((obj, key) => ({
@@ -323,7 +345,7 @@ const search = async function (
323345
// Root catalog with collection links
324346
if (stac && !searchPath) {
325347
const { results } =
326-
await backend.search({}, 'collections', page, limit)
348+
await backend.search({}, 'collections', page, colLimit)
327349
apiResponse = collectionsToCatalogLinks(results, endpoint)
328350
}
329351
// STAC Search
@@ -335,7 +357,7 @@ const search = async function (
335357
// All collections
336358
if (collections && !collectionId) {
337359
const { results, meta } =
338-
await backend.search({}, 'collections', page, limit)
360+
await backend.search({}, 'collections', page, colLimit)
339361
const linkedCollections = addCollectionLinks(results, endpoint)
340362
apiResponse = { meta, collections: linkedCollections }
341363
}
@@ -355,9 +377,9 @@ const search = async function (
355377
// Items in a collection
356378
if (collections && collectionId && items && !itemId) {
357379
const updatedQuery = Object.assign({}, searchParameters.query, {
358-
collection: {
359-
eq: collectionId
360-
}
380+
collections: [
381+
collectionId
382+
]
361383
})
362384
const itemIdParameters = Object.assign(
363385
{}, searchParameters, { query: updatedQuery }

packages/api-lib/libs/es.js

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ async function prepare(index) {
7979
const props = {
8080
'type': 'object',
8181
properties: {
82-
'collection': { type: 'keyword' },
8382
'datetime': { type: 'date' },
8483
'eo:cloud_cover': { type: 'float' },
8584
'eo:gsd': { type: 'float' },
@@ -117,6 +116,7 @@ async function prepare(index) {
117116
dynamic_templates: dynamicTemplates,
118117
properties: {
119118
'id': { type: 'keyword' },
119+
'collection': { type: 'keyword' },
120120
'properties': props,
121121
geometry: {
122122
type: 'geo_shape',
@@ -170,7 +170,7 @@ async function _stream() {
170170
const links = data.links.filter((link) => hlinks.includes(link))
171171
let esDataObject = Object.assign({}, data, { links })
172172
if (index === 'items') {
173-
const collectionId = data.properties.collection
173+
const collectionId = data.collection
174174
const itemCollection =
175175
collections.find((collection) => (collectionId === collection.id))
176176
if (itemCollection) {
@@ -266,7 +266,9 @@ function buildQuery(parameters) {
266266
const inop = 'in'
267267
const { query, intersects } = parameters
268268
let must = []
269+
const should = []
269270
if (query) {
271+
const { collections } = query
270272
// Using reduce rather than map as we don't currently support all
271273
// stac query operators.
272274
must = Object.keys(query).reduce((accumulator, property) => {
@@ -294,8 +296,15 @@ function buildQuery(parameters) {
294296
}
295297
return accumulator
296298
}, must)
299+
300+
if (collections) {
301+
collections.forEach((collection) => {
302+
should.push({ term: { 'collection': collection } })
303+
})
304+
}
297305
}
298306

307+
299308
if (intersects) {
300309
const { geometry } = intersects
301310
must.push({
@@ -310,7 +319,7 @@ function buildQuery(parameters) {
310319
must.push(datetimeQuery)
311320
}
312321

313-
const filter = { bool: { must } }
322+
const filter = { bool: { must, should } }
314323
const queryBody = {
315324
constant_score: { filter }
316325
}
@@ -331,6 +340,16 @@ function buildIdQuery(id) {
331340
}
332341
}
333342

343+
function buildIdsQuery(ids) {
344+
return {
345+
query: {
346+
ids: {
347+
values: ids
348+
}
349+
}
350+
}
351+
}
352+
334353
function buildSort(parameters) {
335354
const { sort } = parameters
336355
let sorting
@@ -355,46 +374,43 @@ function buildSort(parameters) {
355374

356375
function buildFieldsFilter(parameters) {
357376
const id = 'id'
358-
const type = 'type'
359-
const bbox = 'bbox'
360-
const links = 'links'
361-
const assets = 'assets'
362377
const { fields } = parameters
363378
const _sourceInclude = []
364379
const _sourceExclude = []
365380
if (fields) {
366-
const { geometry, includes, excludes } = fields
367-
if (typeof geometry !== 'undefined' && !geometry) {
368-
_sourceExclude.push('geometry')
369-
}
370-
if (includes && includes.length > 0) {
371-
const propertiesIncludes = includes.map(
372-
(field) => (`properties.${field}`)
381+
const { include, exclude } = fields
382+
if (include && include.length > 0) {
383+
const propertiesIncludes = include.map(
384+
(field) => (`${field}`)
373385
).concat(
374-
[id, type, bbox, links, assets]
386+
[id]
375387
)
376388
_sourceInclude.push(...propertiesIncludes)
377389
}
378-
if (excludes && excludes.length > 0) {
379-
const filteredExcludes = excludes.filter((field) =>
380-
(![id, type, bbox, links, assets].includes(field)))
381-
const propertiesExcludes = filteredExcludes.map((field) => (`properties.${field}`))
382-
_sourceExclude.push(...propertiesExcludes)
390+
if (exclude && exclude.length > 0) {
391+
const filteredExcludes = exclude.filter((field) =>
392+
(![id].includes(field)))
393+
const propertiesExclude = filteredExcludes.map((field) => (`${field}`))
394+
_sourceExclude.push(...propertiesExclude)
383395
}
384396
}
385397
return { _sourceExclude, _sourceInclude }
386398
}
387399

388400
async function search(parameters, index = '*', page = 1, limit = 10) {
389401
let body
390-
if (parameters.id) {
402+
if (parameters.ids) {
403+
const { ids } = parameters
404+
body = buildIdsQuery(ids)
405+
} else if (parameters.id) {
391406
const { id } = parameters
392407
body = buildIdQuery(id)
393408
} else {
394409
body = buildQuery(parameters)
395410
}
396411
const sort = buildSort(parameters)
397412
body.sort = sort
413+
logger.info(`Elasticsearch query: ${JSON.stringify(body)}`)
398414

399415
const searchParams = {
400416
index,

packages/api-lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sat-utils/api-lib",
3-
"version": "0.2.6",
3+
"version": "0.3.0",
44
"description": "A library for creating a search API of public Satellites metadata using Elasticsearch",
55
"main": "index.js",
66
"scripts": {

packages/api-lib/tests/fixtures/item.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@
149149
},
150150
"id": "LC80100102015082LGN00",
151151
"links": [],
152+
"collection": "landsat-8-l1",
152153
"properties": {
153-
"collection": "landsat-8-l1",
154154
"datetime": "2015-03-23T15:05:56.200728+00:00",
155155
"eo:cloud_cover": 8.26,
156156
"eo:epsg": 32622,

packages/api-lib/tests/fixtures/stac/LC80100102015050LGN00.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@
166166
"rel": "collection"
167167
}
168168
],
169+
"collection": "landsat-8-l1",
169170
"properties": {
170-
"collection": "landsat-8-l1",
171171
"datetime": "2015-02-19T15:06:12.565047+00:00",
172172
"eo:cloud_cover": 0.54,
173173
"eo:epsg": 32622,

packages/api-lib/tests/fixtures/stac/LC80100102015082LGN00.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@
166166
"rel": "collection"
167167
}
168168
],
169+
"collection": "landsat-8-l1",
169170
"properties": {
170-
"collection": "landsat-8-l1",
171171
"datetime": "2015-03-23T15:05:56.200728+00:00",
172172
"eo:cloud_cover": 8.26,
173173
"eo:epsg": 32622,

0 commit comments

Comments
 (0)