A node-friendly typescript port of https://github.com/awslabs/dynamodb-geo
https://github.com/robhogan/dynamodb-geo.js.git
npm install --save dynamodb-geo or yarn add dynamodb-geo.
const AWS = require('aws-sdk');
const ddb = new AWS.DynamoDB({ endpoint: new AWS.Endpoint('http://localhost:8000') }); // Local development
Next you must create an instance of GeoDataManagerConfiguration for each geospatial table you wish to interact with. This is a container for various options (see API below), but you must always provide a DynamoDB instance and a table name.
const ddbGeo = require('dynamodb-geo');
const config = new ddbGeo.GeoDataManagerConfiguration(ddb, 'MyGeoTable');
You may modify the config to change defaults.
config.longitudeFirst = true; // Use spec-compliant GeoJSON, incompatible with awslabs/dynamodb-geo
Finally, you should instantiate a manager to query and write to the table using this config object.
const myGeoTableManager = new ddbGeo.GeoDataManager(config);
hashKeyLength (optimising for performance and cost)hashKeyLength is the number of most significant digits (in base 10) of the 64-bit geo hash to use as the hash key. Larger numbers will allow small geographical areas to be spread across DynamoDB partitions, but at the cost of performance as more queries need to be executed for box/radius searches that span hash keys. See these tests for an idea of how query performance scales with hashKeyLength for different search radii.
If your data is sparse, a large number will mean more RCUs since more empty queries will be executed and each has a minimum cost. However if your data is dense and hashKeyLength too short, more RCUs will be needed to read a hash key and a higher proportion will be discarded by server-side filtering.
From the AWS Query documentation
DynamoDB calculates the number of read capacity units consumed based on item size, not on the amount of data that is returned to an application. ... The number will also be the same whether or not you use a FilterExpression
Optimally, you should pick the largest hashKeyLength your usage scenario allows. The wider your typical radius/box queries, the smaller it will need to be.
Note that the Java version uses a hashKeyLength of 6 by default. The same value will need to be used if you access the same data with both clients.
This is an important early choice, since changing your hashKeyLength will mean recreating your data.
GeoTableUtil has a static method getCreateTableRequest for helping you prepare a DynamoDB CreateTable request request, given a GeoDataManagerConfiguration.
You can modify this request as desired before executing it using AWS's DynamoDB SDK.
Example:
// Pick a hashKeyLength appropriate to your usage
config.hashKeyLength = 3;
// Use GeoTableUtil to help construct a CreateTableInput.
const createTableInput = ddbGeo.GeoTableUtil.getCreateTableRequest(config);
// Tweak the schema as desired
createTableInput.ProvisionedThroughput.ReadCapacityUnits = 2;
console.log('Creating table with schema:');
console.dir(createTableInput, { depth: null });
// Create the table
ddb.createTable(createTableInput).promise()
// Wait for it to become ready
.then(function () { return ddb.waitFor('tableExists', { TableName: config.tableName }).promise() })
.then(function () { console.log('Table created and ready!') });
myGeoTableManager.putPoint({
RangeKeyValue: { S: '1234' }, // Use this to ensure uniqueness of the hash/range pairs.
GeoPoint: { // An object specifying latitutde and longitude as plain numbers. Used to build the geohash, the hashkey and geojson data
latitude: 51.51,
longitude: -0.13
},
PutItemInput: { // Passed through to the underlying DynamoDB.putItem request. TableName is filled in for you.
Item: { // The primary key, geohash and geojson data is filled in for you
country: { S: 'UK' }, // Specify attribute values using { type: value } objects, like the DynamoDB API.
capital: { S: 'London' }
},
// ... Anything else to pass through to `putItem`, eg ConditionExpression
}
}).promise()
.then(function() { console.log('Done!') });
See also DynamoDB PutItem request
You must specify a RangeKeyValue, a GeoPoint, and an UpdateItemInput matching the DynamoDB UpdateItem request (TableName and Key are filled in for you).
myGeoTableManager.updatePoint({
RangeKeyValue: { S: '1234' },
GeoPoint: { // An object specifying latitutde and longitude as plain numbers.
latitude: 51.51,
longitude: -0.13
},
UpdateItemInput: { // TableName and Key are filled in for you
UpdateExpression: 'SET country = :newName',
ExpressionAttributeValues: {
':newName': { S: 'United Kingdom'}
}
}
}).promise()
.then(function() { console.log('Done!') });
RangeKeyValue and a GeoPoint. Optionally, you can pass DeleteItemInput matching DynamoDB DeleteItem request (TableName and Key are filled in for you).
myGeoTableManager.deletePoint({
RangeKeyValue: { S: '1234' },
GeoPoint: { // An object specifying latitutde and longitude as plain numbers.
latitude: 51.51,
longitude: -0.13
},
DeleteItemInput: { // Optional, any additional parameters to pass through.
// TableName and Key are filled in for you
// Example: Only delete if the point does not have a country name set
ConditionExpression: 'attribute_not_exists(country)'
}
}).promise()
.then(function() { console.log('Done!') });
MinPoint and MaxPoint.
// Querying a rectangle
myGeoTableManager.queryRectangle({
MinPoint: {
latitude: 52.225730,
longitude: 0.149593
},
MaxPoint: {
latitude: 52.889499,
longitude: 0.848383
}
})
// Print the results, an array of DynamoDB.AttributeMaps
.then(console.log);
CenterPoint and RadiusInMeter.
// Querying 100km from Cambridge, UK
myGeoTableManager.queryRadius({
RadiusInMeter: 100000,
CenterPoint: {
latitude: 52.225730,
longitude: 0.149593
}
})
// Print the results, an array of DynamoDB.AttributeMaps
.then(console.log);
GeoDataManagerConfiguration instance. After creating the config object you may modify these properties.
ConsistentRead option (for strongly consistent reads) or not (for eventually consistent reads, at half the cost).
This can also be overridden for individual queries as a query config option.
[lon,lat] ordering, but awslabs/dynamodb-geo uses [lat,lng].
This fork allows you to choose between awslabs/dynamodb-geo compatibility and GeoJSON standard compliance.
false ([lat, lon]) for compatibility with awslabs/dynamodb-geotrue ([lon, lat]) for GeoJSON standard compliance. (default)type attribute in recorded GeoJSON points. Should normally be "Point", which is standards compliant.
Use "POINT" for compatibility with awslabs/dynamodb-geo.
This setting is only relevant for writes. This library doesn't inspect or set this value when reading/querying.
hashKeyLength digits (default 2) of the geo hash, used as the hash (aka partition) part of a hash/range primary key pair. Its value is auto-generated based on item coordinates.
longitudeFirst).
Query results are loaded into memory and processed, it may consume substantial amounts of memory for large datasets.