Navigate to <CF_HOME>/cfusion/bin.
Introduction
ColdFusion, so far, was limited to storing and retrieving data from relational databases only. In existing versions of ColdFusion, you can store and retrieve data using Hibernate or JDBC drivers. In the 2021 release of ColdFusion, you can store and retrieve data from NoSQL databases, for example DynamoDB.
Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale. It's a fully managed, multi-region, database with built-in security, backup and restore, and in-memory caching for internet-scale applications.
With DynamoDB, you can create database tables that store and retrieve any amount of data and serve any level of request traffic. You can scale up or scale down your tables' throughput capacity without downtime or performance degradation and use the AWS Management Console to monitor resource utilization and performance metrics.
For more information, see Amazon DynamoDB.
Indexing in DynamoDB
Amazon DynamoDB provides faster access to items in a table by specifying primary key values. However, many applications might benefit from having one or more secondary (or alternate) keys available, to allow efficient access to data with attributes other than the primary key. To address this, you can create one or more secondary indexes on a table, and issue Query requests against these indexes.
A secondary index is a data structure that contains a subset of attributes from a table, along with an alternate key to support Query operations. You can retrieve data from the index using a Query, like the way you issue a query in a table. A table can have multiple secondary indexes, which gives your applications access to many different query patterns.
There are two types of secondary indexes in DynamoDB:
- Global secondary index — an index with a partition key and a sort key that can be different from those on the base table. A global secondary index is considered "global" because queries on the index can span all the data in the base table, across all partitions.
- Local secondary index — an index that has the same partition key as the base table, but a different sort key. A local secondary index is "local" in the sense that every partition of a local secondary index is scoped to a base table partition that has the same partition key value.
Supported data types
DynamoDB has a defined set of data types that it supports. The following data types are supported currently:
- All Numbers – N
- All Strings – S
- All Boolean values – BOOL
- Binary – B
- Null – NULL
- Lists – L
- Map – M
- Sets – LS, BS, SS
Get started
Install awsdynamodb module
Adobe ColdFusion (2021 release) is modularized, if you are only using the ZIP installer. By default, the module for AWS DynamoDB is not installed. The first step is to install the DynamoDB package in ColdFusion.
Note: If you are using the GUI installer, the packages are pre-installed.
The package for SNS is called awsdynamodb.
To install the package awsdynamodb, use the Package Manager page in the ColdFusion Administrator, or follow the steps below:
-
-
Enter the command:
- Windows: cfpm.bat
- Linux: cfpm.sh
-
Enter the command, install awsdynamodb.
Wait for the DynamoDB service to get installed.
Get credentials to access DynamoDB
When you interact with AWS, you specify your AWS security credentials to verify your credentials and check whether you have permission to access the resources that you are requesting.
AWS uses the security credentials to authenticate and authorize your requests.
You must get the AWS Access Key ID and the AWS Secret Access Key. For more information, see Access Keys.
Add cloud service credentials
In this release of ColdFusion, there is a new method getCloudService() that gives you a handle to create objects for accessing various cloud services.
The syntax of the service handle is as follows:
service=getCloudService(cloudCred,cloudConfig), where:
- cloudCred: Defines the credentials for the cloud service. It could either be a struct or a string (also known as credential alias).
- cloudConfig: Defines the cloud service configuration details. It could either be a struct or a string (also known as config alias).
After you've acquired the AWS credentials, you must declare these credentials in one of the following ways. Only then you can use these credentials to create a DynamoDB object, after which you can use the object to make calls to the various DynamoDB methods.
ColdFusion Administrator
Set credentials
In the ColdFusion Administrator, click Data & Services > Cloud Credentials.
Enter the following details, like credentials Alias, Vendor, and the credentials.
An alias is a named representation of a cloud service and its configuration details. You can set the config alias through ColdFusion Administrator.
After entering the details, click Add Credentials.
Set configuration options
In the ColdFusion Administrator, click Data & Services > Cloud Configuration.
Enter the following details, like configuration Alias, Vendor, and the name of the service.
After adding the configuration options, you may need to add a few more options. You can do so in the next screen. The following are the option categories that you may need to add:
- Request config
- Client config
- Proxy settings
- Retry policy
- Retry conditions
Create the object
Once you've created the aliases for DynamoDB credential and configuration options, you can create the object by using the getCloudService API. For example,
dynamoObject = getCloudService("dynamoCred", "dynamoConf")
Application.cfc
You can specify the DynamoDB credentials and configuration options in Application.cfc. For example,
component { this.name="MyApp" function OnApplicationStart() { application.DynamoProfile = { "credentialAlias" : "Alias Name", "vendorName" : "AWS", "region" : "Region Name", "secretAccessKey" : "Access Secret", "accessKeyId" : "Access Key" } application.DynamoCred = { "serviceName" = "DYNAMODB" } } }
Create the object
dynamoObject = getCloudService(application.DynamoProfile, application.DynamoCred)
On CFM page
On a CFM page, you can specify the DynamoDB credentials and configuration options in one of the four methods, specified below:
Credential alias and configuration alias
After you've created the aliases for DynamoDB credential and configuration options, you can use these aliases in the getCloudService handle as shown below:
<cfscript> // define the credential and the configuration aliases in the ColdFusion Admin dynamo=getCloudService("dynamoCred","dynamoConf") // List all DynamoDB tales in the account listTablesStruct = { "Limit": 50 } listTablesResponse =dynamo.ListTables(listTablesStruct); writeDump(listTablesResponse) </cfscript>
Credential Alias and Struct for configuration options
<cfscript> // Using credential alias and struct for service config dynamoConf = { "alias":"dynamoConf", "serviceName" : "DYNAMODB", "clientOverrideConfig":{ "retryPolicy":{ "numRetries":4 } }, "httpClientConfig":{ "maxConnections":50 } } dynamo = getCloudService("dynamoCred", dynamoConf) // List all DynamoDB tales in the account listTablesStruct = { "Limit": 50 } listTablesResponse =dynamo.ListTables(listTablesStruct); writeDump(listTablesResponse) </cfscript>
Configuration alias and struct for credentials
<cfscript> // Using config alias and struct for service credentials // dynamo credentials dynamoCreds={ "vendorName":"AWS", alias": "dynamoCred", "region":"us-east-2", "accessKeyId": "access key", "secretAccessKey": "secret access" } dynamo = getCloudService(dynamoCreds, "dynamoConf") // List all DynamoDB tales in the account listTablesStruct = { "Limit": 50 } listTablesResponse =dynamo.ListTables(listTablesStruct); writeDump(listTablesResponse) </cfscript>
Structs for both credential and configuration options
<cfscript> // Using Structs for both cloud credential and config dynamoCred={ "vendorName":"AWS", "credentialAlias": "dynamoCred", "region":"us-east-2", "accessKeyId": "access key", "secretAccessKey": "secret access key" } dynamoConf = { "alias":"dynamoConf", "serviceName" : "DYNAMODB", "clientOverrideConfig":{ "retryPolicy":{ "numRetries":4 } }, "httpClientConfig":{ "maxConnections":50 } } dynamo = getCloudService(dynamoCred, dynamoConf) // List all DynamoDB tales in the account listTablesStruct = { "Limit": 50 } listTablesResponse =dynamo.ListTables(listTablesStruct); writeDump(listTablesResponse) </cfscript>
Admin API
You can also add DynamoDB credentials and configuration options by using the Admin APIs. The methods to add credentials and configuration are available in cloud.cfc.
The examples below demonstrate the usage of the methods addCredential(struct credential) and addServiceConfig(struct config).
Add credentials
<cfscript> // Create an object of administrator component and call the login method adminObj = createObject("component","cfide.adminapi.administrator") adminObj.login("admin") // Create an object of cloud component cloudObj = createObject("component","cfide.adminapi.cloud") // define credentials struct credentialStruct={ "alias" : "CredDynamo", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access key", "accessKeyId" : "access key" } // add credential credentialStruct try{ cloudObj.addCredential(credentialStruct) writeOutput("Credentials added successfully") } catch(any e){ writeDump(e) } </cfscript>
Add configuration
<cfscript> // Create an object of administrator component and call the login method adminObj = createObject("component","cfide.adminapi.administrator") adminObj.login("admin") // Create an object of cloud component cloudObj = createObject("component","cfide.adminapi.cloud") // define configuration struct configStruct={ "alias":"ConfDynamo", "serviceName":"DYNAMODB", "clientOverrideConfig":{ "retryPolicy":{ "numRetries":4 } }, "httpClientConfig":{ "maxConnections":50 } } // add config configStruct try{ cloudObj.addServiceConfig(configStruct) writeOutput("Configuration service added successfully") } catch(any e){ writeDump(e) } </cfscript>
cfsetup
Cloud Credential
Add
- add cloudcredential vendorName=AWS accessKeyId=SomeAccessKeyId secretAccessKey=SomeSecretKey region=us-west-1 alias=myAliasForCloudCredential
Set
- set cloudcredential myAliasForCloudCredential accessKeyId=newAccessKeyId
- set cloudcredential myAliasForCloudCredential secretAccessKey=newSecretAccessKey
- set cloudcredential myAliasForCloudCredential region=us-west-2
Get
- get cloudcredential myAliasForCloudCredential vendorName
- get cloudcredential myAliasForCloudCredential accessKeyId
- get cloudcredential myAliasForCloudCredential secretAccessKey
- get cloudcredential myAliasForCloudCredential region
- get cloudcredential myAliasForCloudCredential alias
Show
- show cloudcredential
- show cloudcredential myAliasForCloudCredential
Delete
- delete cloudcredential myAliasForCloudCredential
CloudConfiguration
Add
- add cloudconfiguration serviceName=DYNAMODB alias=configAlias accelerateModeEnabled=true chunkedEncodingEnabled=true dualStackEnabled=true pathStyleAccessEnabled=true checksumValidationEnabled=true maxConnections=50 connectionMaxIdleTime=10s useIdleConnectionReaper=true socketTimeout=10s expectContinueEnabled=true connectionTimeout=10s connectionTimeToLive=10s connectionAcquisitionTimeout=10s useSystemPropertyValues=true numRetries=5 apiCallAttemptTimeout=2s
Set
- set cloudconfiguration configAlias maxconnections=40
- set cloudconfiguration configAlias maxconnections=40 numRetries=6
Get
- get cloudconfiguration configAlias serviceName
- get cloudconfiguration configAlias serviceName maxconnections
- get cloudconfiguration configAlias maxconnections
Show
- show cloudconfiguration
- show cloudconfiguration configAlias
Delete
- delete cloudconfiguration configAlias
Make DynamoDB requests
To make requests to DynamoDB using ColdFusion, you must the object that you had created using the service handle, getCloudService.
As an example, scan a table in DynamoDB, where you'd view all the items in the table and their attributes. To view the response, you must specify two parameters to the method Scan. These are:
- Body of the request
- Customization options
Request parameters
Create a struct that contains all the request parameters. To scan a DynamoDB table, you must pass these request parameters as a struct. For a list of all the request parameters, see Scan API.
tableName="MusicTableForDemo" scanStruct = { "TableName": "#tableName#" }
Customization options
The second parameter contains a few customizations that ColdFusion provides, which customizes the response.
This parameter is optional. If you do not want any of these customizations, you can pass an empty struct, or leave this parameter blank.
The supported optimizations are:
- HasType: Boolean (Default: false)
- CustomResponse: Boolean (Default: false)
- BinaryFormat: Boolean (Default: false)
- PreserveCFC: Boolean (Default: false)
- CachedWithin: Used for caching
- CachedAfter: Used for caching
- CacheId: Used for caching
- CacheRegion: Used for caching
hastype
Defines if the request data is assigned a type (for ex. S, L, M, etc). Values are True or False. Default value is False.
If specified as true, you will need to specify the types for all the datatypes being sent
If specified as false, ColdFusion will auto determine the type of the data. This is useful if you want to send a ColdFusion PDF. Spreadsheet, Query, CFC object to Dynamo but don’t want to manually serialize this data.
<cfscript> dynamo=getCloudService(application.awsCred, application.dynamoConf) movieName="Movies010" // Stage 1: create a table tableStruct={ TableName : "#movieName#", KeySchema:[ { AttributeName: "year", KeyType: "HASH"}, { AttributeName: "title", KeyType: "RANGE"} ], AttributeDefinitions:[ { AttributeName: "year", AttributeType: "N" }, { AttributeName: "title", AttributeType: "S" } ], ProvisionedThroughput:{ ReadCapacityUnits: 10, WriteCapacityUnits: 10 } } dynamo.createTable(tableStruct) sleep(3000) // Stage 2: insert an item into the table putItemStruct={ "TableName":"#movieName#", "Item":{ "year": {"N": 2019}, "title": {"S": "Golden"} }, "ReturnValues": "NONE" } try{ putItemResponse=dynamo.putItem(putItemStruct,{"hasType": true}) writeOutput("Item inserted successfully in the table.") writeDump(putItemResponse) } catch (any e){ writeDump(e) } </cfscript>
customResponse
Defines if you want to see the response data with types (for ex. S, L, M, etc). Values are True or False. Default value is false
If true, the response from AWS won’t have the datatypes in the result struct. This is useful if you have sent a PDF/Spreadsheet/Query/CFC/Image object when writing data to DynamoDB. If you want to retrieve the data in ColdFusion object itself, you need to use the option customResponse: true.
If false, the response will show the various AWS DynmaoDB datatypes in response map.
<cfscript> // credentials and configuration dynamo = getCloudService(application.awsCred,application.dynamoConf) tableName="MusicTableForDemo" scanStruct = { "TableName": "#tableName#" } scanResponse=dynamo.scan(scanStruct,{"customResponse":true}) arr=scanResponse.items writeOutput("<b>List of songs</b>" & "") mapFunction=function(item){ writeOutput(item.SongTitle & "<br/>") } arr.map(mapFunction) </cfscript>
binaryFormat
The binaryFormat attribute customizes the data fields, which are binary in nature. When the value is true, it returns raw binary data. When the value is false, it returns Base64 Encoded data, as returned by DynamoDB. It works only when customResponse: true.
For example,
<cfscript> // credentials and configuration dynamo = getCloudService(application.awsCred,application.dynamoConf) tableName="MusicTableForDemo" scanStruct = { "TableName": "#tableName#" } scanResponse=dynamo.scan(scanStruct,{"customResponse":true,"binaryFormat":true}) arr=scanResponse.items writeOutput("<b>List of songs</b>" & "") mapFunction=function(item){ writeOutput(item.SongTitle & "<br/>") } arr.map(mapFunction) </cfscript>
preserveCFC
Defines if you want to send a CFC to a DynamoDB object. It works only when hasType: false. PreserveCFC must be set to true for deserializeCFC option to work while retrieving back CFC.
Employee.cfc
component accessors="true" { property string empName; property numeric age; property string dept; }
Helper.cfc
component accessors="true" { public function putItemCFC(dynamoObject, itemStruct, hasType, preserveCfc) { result = dynamoObject.putItem(itemStruct, {"hasType": hasType, "preserveCFC": preserveCfc}); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Items written successfully<br />"); } else { writeOutput("Failed to write the items<br />"); writeDump(result) } } }
SerializeCFC.cfm
<cfscript> empData = new Employee({empName="James", age=26, dept="000"}); region1 = "ap-northeast-2"; // credentials and configuration dynamo = getCloudService(application.awsCred,application.dynamoConf) tableName = "Table_Test_CFC"; TablePartitionKey = "OrderId"; partitionKeyType = "N"; TableSortKey = "OrderName"; sortKeyType = "S"; MyCFCKey = "OrderCFC"; LocalSecondaryIndexSortKey = "OrderDateTime"; secondaryIndexSortKeyType = "S"; myComponent = createObject("Component", "helper"); try { myComponent.deleteTable(dynamoUsWest1, tableName) } catch (any e) { writeDump(e) } try { myComponent.createTableWithLocalIndex(dynamoUsWest1, tableName, TablePartitionKey, partitionKeyType, TableSortKey, sortKeyType, LocalSecondaryIndexSortKey, secondaryIndexSortKeyType) sleep(20000); } catch (any e) { writeDump(e) } orderName = "MyOrder: "; strct_putItem = { "TableName": tableName, "Item":{ "#TablePartitionKey#": 2, "#TableSortKey#": "MyOrder: 2", "CUSTOMER_KEY": "0001-23456", "OrderStatus": "CONFIRMED", "Year": 2012, "#LocalSecondaryIndexSortKey#": "2020/04/21", "#MyCFCKey#": empData } } try { result = dynamoObject.putItem(itemStruct, {"hasType": false, "preserveCFC": true}); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Items written successfully<br />"); } else { writeOutput("Failed to write the items<br />"); writeDump(result) } } catch (any e) { writeDump(e) } </cfscript>
If you want to get back a CFC object from DynamoDB, use Preservecfc as true. Works only with customResponse: true. PreserveCFC must be true while the CFC object was stored to dynamodb.
CachedWithin
Defines the timeframe till which we want to cache our queries. After this time, cache items will not be available. It will be automatically purged.
There is an option Clear Dynamo Cache Now in Server Settings > Caching in ColdFusion Administrator. Clicking the button clears the Dynamo cache.
<cfscript> // credentials and configuration dynamo = getCloudService(application.awsCred,application.dynamoConf) posdateresult=DateAdd("s", 30, now()) tableName="MusicTableForDemo" scanStruct = { "TableName": "#tableName#" } scanResponse=dynamo.scan(scanStruct,{"customResponse":true, cachedWithin: "#createTimeSpan( 0, 0, 0, 30 )#"}) arr=scanResponse.items writeOutput("<b>List of songs</b>" & "") mapFunction=function(item){ writeOutput(item.SongTitle & "<br/>") } arr.map(mapFunction) </cfscript>
CachedAfter
Defines the time after which we want to cache our queries. Cached items will be available only after this time.
There is an option Clear Dynamo Cache Now in Server Settings > Caching in ColdFusion Administrator. Clicking the button clears the Dynamo cache.
<cfscript> // credentials and configuration dynamo = getCloudService(application.awsCred,application.dynamoConf) posdateresult=DateAdd("s", 30, now()) tableName="MusicTableForDemo" scanStruct = { "TableName": "#tableName#" } scanResponse=dynamo.scan(scanStruct,{"customResponse":true,cachedAfter: posdateresult}) arr=scanResponse.items writeOutput("<b>List of songs</b>" & "") mapFunction=function(item){ writeOutput(item.SongTitle & "<br/>") } arr.map(mapFunction) </cfscript>
For inline service config, the alias key is mandatory for query Caching to work properly.
Example
config = {
"alias": "myConfig",
"serviceName" : "DYNAMODB"
};
For admin portal, alias is already mandatory.
Named parameters
ColdFusion DyanamoDB API’s also supports named parameters for its attributes
They are named:
- Query
- Options
Query parameter takes in the payload that needs to be sent.
For ex: For Scan of a table, it can be query={TableName: “yourTable”}
Options parameter is a struct mentioning all the options DynamoDB supports
For ex: hasType, customResponse, etc.
Options={hasType: true}
<cfscript> dynamo=getCloudService(application.awsCred, application.dynamoConf) movieName="Movies010" // Stage 1: create a table tableStruct={ TableName : "#movieName#", KeySchema:[ { AttributeName: "year", KeyType: "HASH"}, { AttributeName: "title", KeyType: "RANGE"} ], AttributeDefinitions:[ { AttributeName: "year", AttributeType: "N" }, { AttributeName: "title", AttributeType: "S" } ], ProvisionedThroughput:{ ReadCapacityUnits: 10, WriteCapacityUnits: 10 } } dynamo.createTable(tableStruct) sleep(3000) // Stage 2: insert an item into the table putItemStruct={ "TableName":"#movieName#", "Item":{ "year": {"N": 2019}, "title": {"S": "Golden"} }, "ReturnValues": "NONE" } try{ putItemResponse=dynamo.putItem(query = putItemStruct, options = {"hasType": true}) writeOutput("Item inserted successfully in the table.") writeDump(putItemResponse) } catch (any e){ writeDump(e) } </cfscript>
Case-sensitive struct
A struct in ColdFusion is case-insensitive, while DynamoDB is case sensitive. To address this issue, a new struct type, casesensitive, is introduced, which preserves case. You can pass a request to DynamoDB in ColdFusion using the following:
- Struct or
- CaseSensitiveStruct
When dealing with DynamoDB methods, we recommend using case sensitive structs, as DynamoDB is case sensitive and there is no data loss due to case insensitivity.
For example,
cfscript> cred = { "credentialAlias" : "MyCredential", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; "accessKeyId" : "XXXXXXXXXXXXXXXXX" } config = { "serviceName" = "DYNAMODB" }; dynamo = getCloudService(cred, config); strct = structNew("casesensitive"); strct.TableName = "College" writedump(strct); result = dynamo.scan(strct, {} ); writedump(result); </cfscript>
Advanced datatype support
The following data types are supported:
- CFC: Use the option, preserveCFC as true.
- Date
- BigDecimal
- PDF: Use any cfpdf methods on the binary response object.
- Query: Use the method QueryNew on the AWS response object.
- Image
- Spreadsheet: Use the method SpreadSheetRead and pass the response object in binary.
- XML: Use the method DeserializeXML on the AWS response object.
The example below illustrates how you can tore and retrieve a spreadsheet object in DynamoDB using ColdFusion.
Spreadsheet
helperFuctions.cfc
component { function getLocalSecondaryIndex(partitionKey, sortKey, tableName) { localSecondaryIndex = [{ "IndexName": "LocalIndex_" & tableName, "KeySchema": [ { "AttributeName": partitionKey, "KeyType": "HASH" }, { "AttributeName": sortKey, "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "KEYS_ONLY" } }] return localSecondaryIndex; } function getGlobalSecondaryIndex(partitionKey, sortKey, tableName) { globalSecondaryIndex = [{ "IndexName": "GlobalIndex_" & tableName, "KeySchema": [ { "AttributeName": partitionKey, "KeyType": "HASH" }, { "AttributeName": sortKey, "KeyType": "RANGE" } ], "Projection": { "ProjectionType": "KEYS_ONLY" }, "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 10 } }] return globalSecondaryIndex; } function getCreateTableStruct(tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType) { createTable = { "TableName": tableName, "KeySchema": [ { "AttributeName": partitionKeyName, "KeyType": "HASH" }, { "AttributeName": sortKeyName, "KeyType": "RANGE" } ], "AttributeDefinitions": [ { "AttributeName": partitionKeyName, "AttributeType": partitionKeyType }, { "AttributeName": sortKeyName, "AttributeType": sortKeyType } ], "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 10 }, "StreamSpecification": { "StreamEnabled": true, "StreamViewType": "NEW_AND_OLD_IMAGES" } } return createTable; } public function createTable(dynamoObject, tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType) { createTable = getCreateTableStruct(tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType); try { result = dynamoObject.createTable(createTable); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Creating the table<br />"); } else { writeOutput("Failed to create the table<br />"); } } catch (any e) { writeDump(e) } } public function createTableWithLocalIndex(dynamoObject, tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType, localSortKey, localSortKeyType) { createTable = getCreateTableStruct(tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType); localIndex = getLocalSecondaryIndex(partitionKeyName, localSortKey, tableName) structInsert(createTable, "LocalSecondaryIndexes", localIndex); attributeDefinitionArray = structFind(createTable, "AttributeDefinitions") myStruct = structNew(); myStruct["AttributeName"] = localSortKey; myStruct["AttributeType"] = localSortKeyType; arrayAppend(attributeDefinitionArray, myStruct) structUpdate(createTable, "AttributeDefinitions", attributeDefinitionArray); try { result = dynamoObject.createTable(createTable); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Creating the table<br />"); } else { writeOutput("Failed to create the table<br />"); } } catch (any e) { writeDump(e) } } public function createTableWithGlobalIndex(dynamoObject, tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType, globalPartitionKey, globalPartitionKeyType, globalSortKey, globalSortKeyType) { createTable = getCreateTableStruct(tableName, partitionKeyName, partitionKeyType, sortKeyName, sortKeyType); globalIndex = getGlobalSecondaryIndex(globalPartitionKey, globalSortKey, tableName) structInsert(createTable, "GlobalSecondaryIndexes", globalIndex); attributeDefinitionArray = structFind(createTable, "AttributeDefinitions") myStruct = structNew(); myStruct["AttributeName"] = globalPartitionKey; myStruct["AttributeType"] = globalPartitionKeyType; arrayAppend(attributeDefinitionArray, myStruct) myStruct1 = structNew(); myStruct1["AttributeName"] = globalSortKey; myStruct1["AttributeType"] = globalSortKeyType; arrayAppend(attributeDefinitionArray, myStruct1) structUpdate(createTable, "AttributeDefinitions", attributeDefinitionArray); try { result = dynamoObject.createTable(createTable); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Creating the table<br />"); } else { writeOutput("Failed to create the table<br />"); } } catch (any e) { writeDump(e) } } public function deleteTable(dynamoObject, tableName) { deleteTable = { TableName: tableName } try { result = dynamoObject.deleteTable(deleteTable); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Deleting the table<br />"); } } catch (any e) { if(e.ExceptionDetails.ExceptionCode eq "ResourceNotFoundException") { writeOutput("Deleting the table<br />"); } else { writeOutput("Failed to delete the table<br />"); writeDump(e) } } } public function createGlobalTable(dynamoObject, tableName, replicaRegion1, replicaRegion2) { createGlobalTable = { "GlobalTableName": tableName, "ReplicationGroup": [ { "RegionName": replicaRegion1 }, { "RegionName": replicaRegion2 } ] } public function putItem(dynamoObject, itemStruct, hasType) { result = dynamoObject.putItem(itemStruct, {"hasType": hasType}); if(result.HttpResponse.StatusCode eq 200) { writeOutput("Items written successfully<br />"); } else { writeOutput("Failed to write the items<br />"); writeDump(result) } } }
sp.cfm
<cfscript> region1 = "us-west-1"; cred_west1 = { "alias" : "alias", "vendorName" : "AWS", "region" : region1, "secretAccessKey" : "secret access key", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" }; dynamoUsWest1 = getCloudService(cred_west1, config); tableName = "Table_Cache_GetItem_1"; TablePartitionKey = "OrderId"; partitionKeyType = "N"; TableSortKey = "OrderName"; sortKeyType = "S"; LocalSecondaryIndexSortKey = "OrderDateTime"; secondaryIndexSortKeyType = "S"; myComponent = createObject("Component", "helperFunctions"); try { myComponent.deleteTable(dynamoUsWest1, tableName) } catch (any e) { writeDump(e) } try { myComponent.createTableWithLocalIndex(dynamoUsWest1, tableName, TablePartitionKey, partitionKeyType, TableSortKey, sortKeyType, LocalSecondaryIndexSortKey, secondaryIndexSortKeyType) sleep(20000); } catch (any e) { writeDump(e) } orderName = "MyOrder: "; strct_putItem = { "TableName": tableName, "Item":{ "#TablePartitionKey#": 2, "#TableSortKey#": "MyOrder: ", "CUSTOMER_KEY": "0001-23456", "OrderStatus": "CONFIRMED", "Year": 2012, "#LocalSecondaryIndexSortKey#": "2020/04/21" } } for(i = 1; i < 5; i++) { structUpdate(strct_putItem.Item, "#TablePartitionKey#", i); structUpdate(strct_putItem.Item, "#TableSortKey#", orderName & i); myComponent.putItem(dynamoUsWest1, strct_putItem, "false") sleep(10000) } strct_getItem = { "TableName": tableName, "Key": { "#TablePartitionKey#": 2, "#TableSortKey#": "MyOrder: 2" }, "ExpressionAttributeNames": { "##Yr": "Year" }, "ProjectionExpression": "#TablePartitionKey#, ##Yr, OrderStatus", "ConsistentRead": false, "ReturnConsumedCapacity": "INDEXES" } try { result = dynamoUsWest1.getItem(strct_getItem, {CustomResponse: true, cachedWithin: "#createTimeSpan( 0, 0, 0, 45 )#"}); if( (result.ConsumedCapacity.CapacityUnits == 0.5) && (!structKeyExists(result.Item, "CUSTOMER_KEY")) && (result.Item.OrderId == 2) && (result.Item.Year == 2012) && (structKeyExists(result.ConsumedCapacity, "Table")) ) { writeOutput("SUCCESS<br />"); } else { writeOutput("FAIL<br />"); } } catch (any e) { writeDump(e); } strct_putItem = { "TableName": tableName, "Item":{ "#TablePartitionKey#": 2, "#TableSortKey#": "MyOrder: 2", "CUSTOMER_KEY": "0001-23456", "OrderStatus": "CONFIRMED", "Year": 2020, "#LocalSecondaryIndexSortKey#": "2020/04/21" } } myComponent.putItem(dynamoUsWest1, strct_putItem, "false") sleep(10000) try { result = dynamoUsWest1.getItem(strct_getItem, {CustomResponse: true, cachedWithin: "#createTimeSpan( 0, 0, 0, 45 )#"}); if( (result.ConsumedCapacity.CapacityUnits == 0.5) && (!structKeyExists(result.Item, "CUSTOMER_KEY")) && (result.Item.OrderId == 2) && (result.Item.Year == 2012) && (structKeyExists(result.ConsumedCapacity, "Table")) ) { writeOutput("SUCCESS<br />"); } else { writeOutput("FAIL<br />"); } } catch (any e) { writeDump(e); } sleep(36000) try { result = dynamoUsWest1.getItem(strct_getItem, {CustomResponse: true, cachedWithin: "#createTimeSpan( 0, 0, 0, 45 )#"}); if( (result.ConsumedCapacity.CapacityUnits == 0.5) && (!structKeyExists(result.Item, "CUSTOMER_KEY")) && (result.Item.OrderId == 2) && (result.Item.Year == 2020) && (structKeyExists(result.ConsumedCapacity, "Table")) ) { writeOutput("SUCCESS<br />"); } else { writeOutput("FAIL<br />"); } } catch (any e) { writeDump(e); } try { myComponent.deleteTable(dynamoUsWest1, tableName) } catch (any e) { writeDump(e) } </cfscript>
DynamoDB functions
Table functions
Like all SQL and NoSQL databses, Amazon DynamoDB stores data in tables. The following are some of the operations that you can perform in a DynamoDB table.
Create a table
To create a table, use the function createTable. To create the table, you must provide the following:
- Name of the table
- Primary key: The primary key consists of one attribute (partition key) or two attributes (partition key and sort key). You must provide the attribute names, data types, and the role of each attribute: HASH (for a partition key) and RANGE (for a sort key).
- Throughput settings: Specify the initial read and write throughput settings for the table.
The example below creates the table MusicForMe. The primary key consists of Artist (partition key) and SongTitle (sort key), with both the keys having a data type of String. The maximum throughput for this table is 10 read capacity units and 5 write capacity units.
<cfscript> cred = { "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" } dynamo = getCloudService(cred, config) createTableStruct={ TableName:"MusicForMe", AttributeDefinitions:[ {AttributeName:"Artist",AttributeType:"S"}, {AttributeName:"SongTitle",AttributeType:"S"} ], KeySchema:[ {AttributeName:"Artist",KeyType:"HASH"}, {AttributeName:"SongTitle",KeyType:"RANGE"} ], ProvisionedThroughput:{ ReadCapacityUnits: 10, WriteCapacityUnits: 10 } } try{ createTableResponse=dynamo.createTable(createTableStruct,{"customResponse": true}) writeOutput("Table created successfully") writeDump(createTableResponse) } catch(any e){ writeDump(e) } </cfscript>
Describe a table
After creating the table, you may want to view the table information, like:
- Attributes
- Date of creation
- Global Secondary Indexes
- Local Secondary Indexes
- Schema
- Provisioned Throughput
Use the function describeTable for viewing the information of a table.
The example below describes the table MusicForMe, which was created in the previous section.
<cfscript> cred = { "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" } dynamo = getCloudService(cred, config) // let's retrieve information about the table "MusicForMe" if (ArrayContains(listTablesResponse.TableNames,"MusicForMe")){ describeTableStruct={ "TableName":"YearlyProductCatalog" } describeTableResponse=dynamo.describeTable(describeTableStruct) writeDump(describeTableResponse) } else{ writeOutput("Table not found") } </cfscript>
Update a table
Updating a DynamoDB table involves either modifying the table's provisioned settings or read/write capacity modes or the global secondary indexes on the table.
For more information, see updateTable.
The example below updates the values of the read and the write capacity units of the table MusicForMe.
<cfscript> cred = { "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" } dynamo = getCloudService(cred, config) tableName="MusicForMe" oldReadCapacityUnits=10 oldWriteCapacityUnits=10 newReadCapacityUnits=50 newWriteCapacityUnits=50 updateTableStruct={ "TableName": "#tableName#", "ProvisionedThroughput": { "ReadCapacityUnits": "#newReadCapacityUnits#", "WriteCapacityUnits": "#newWriteCapacityUnits#" } } try{ updateTableResponse=dynamo.updateTable(updateTableStruct) if( (updateTableResponse.HttpResponse.StatusCode==200) and (updateTableResponse.TableDescription.ProvisionedThroughput.ReadCapacityUnits==oldReadCapacityUnits) and (updateTableResponse.TableDescription.ProvisionedThroughput.WriteCapacityUnits==oldWriteCapacityUnits) and (updateTableResponse.TableDescription.TableStatus=="UPDATING") ) { writeOutput("Old read and write values correct.") } else { writeOutput("Old read and write values incorrect.") } } catch(any e){ writeDump(e) } </cfscript>
Delete a table
Delete a table created previously by using the deleteTable function. Once you delete the table, you cannot restore it.
The example below deletes the table MusicForMe.
<cfscript> cred = { "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" } dynamo = getCloudService(cred, config) tableName="MusicForMe" // delete the table deleteTableStruct={ "TableName": "#tableName#" } try{ deleteResponse=dynamo.deleteTable(deleteTableStruct) writeOutput("Table deleted successfully") writeDump(deleteResponse) } catch (any e){ writeOutput("Unable to delete the table") writeDump(e) } </cfscript>
List all tables
To see all the tables in your AWS region and account, use the function listTables.
This function returns an array of all the tables in your account.
The example below returns the names of a maximum of 50 tables that exist in your account. You can change the limit accordingly.
<cfscript> cred={ "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } conf={ "serviceName"="DYNAMODB" } dynamo=getCloudService(cred, conf) params = { "Limit": 50 } result = dynamo.ListTables(params); writeDump(result) </cfscript>
Write data to the table
After creating the table, you must populate the table with data. The following are the operations you can perform in the table:
Insert an item
Insert an item to the table. Use the function putItem to insert a new item. If an item with the same key already exists in the table, it is replaced with the new item.
The example creates a table NewProductCatalog and inserts an item to the table.
<cfscript> cred={ "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } conf={ "serviceName"="DYNAMODB" } dynamo=getCloudService(cred, conf) tableName="NewProductCatalog" // Stage 1: Create a table createTableStruct={ "TableName": "#tableName#", "KeySchema": [ { "AttributeName": "id", "KeyType": "HASH" } ], "AttributeDefinitions": [ { "AttributeName": "id", "AttributeType": "N" } ], "ProvisionedThroughput": { "ReadCapacityUnits": 10, "WriteCapacityUnits": 10 } } dynamo.createTable(createTableStruct) sleep(20000) // Stage 2: Insert an item putItemStruct = { "TableName": "#tableName#", "Item":{ "id": { "N": 250 }, "Title": { "S": "Hamlet" }, "Price": { "N": "20" } }, "ReturnValues": "ALL_OLD" } try{ putItemResponse=dynamo.putItem(putItemStruct,{"hasType": true}) writeOutput("Item inserted successfully") writeDump(putItemResponse) } catch (any e){ writeDump(e) } </cfscript>
Update an item
After inserting the item, you can update the item by using the updateItem function.
If an item with the specified key does not exist, the function creates an item. Otherwise, it modifies the existing item's attributes.
<cfscript> cred={ "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } conf={ "serviceName"="DYNAMODB" } dynamo=getCloudService(cred, conf) tableName="NewProductCatalog" // update the item that was inserted updateItemStruct={ "TableName": "#tableName#", "Key": { "id": { "N": 250 } }, "UpdateExpression": "set Title = :val1", "ConditionExpression": "Price = :val2", "ExpressionAttributeValues": { ":val1": {"S": "Macbeth"}, ":val2": {"N": "200"} }, "ReturnValues": "ALL_NEW" } try{ result = dynamo.updateItem(updateItemStruct, {"hasType": true}) if(result.Attributes.Title.S == "Hamlet") { writeOutput("Title changed successfully<br/>") } else { writeOutput("Failed to change the title<br/>") } } catch (any e){ writeDump(e) } </cfscript>
Delete an item
Delete an item in the table by using the deleteItem function.
<cfscript> cred = { "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } config = { "serviceName" = "DYNAMODB" } dynamo = getCloudService(cred, config) tableName="YearlyProductCatalog" // items to delete id=550 title="hamlet" // delete the item in the table deleteItemStruct={ "TableName":"#tableName#", "Key":{ "id":{"N":"#id#"}, "title":{"S":"#title#"} }, "ReturnValues": "ALL_OLD" } try{ deleteItemResponse=dynamo.deleteItem(deleteItemStruct,{"hasType": true}) writeOutput("Item deleted successfully") writeDump(deleteItemResponse) } catch(any e){ writeDump(e) } </cfscript>
Read an item from the table
To read an item from a DynamoDB table, use the function getItem. You must provide the name of the table, along with the primary key of the item you want.
<cfscript> cred={ "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } conf={ "serviceName"="DYNAMODB" } dynamo=getCloudService(cred, conf) // create a table tableName="MusicForAll" createTableStruct={ TableName:"#tableName#", AttributeDefinitions:[ {AttributeName:"Artist",AttributeType:"S"}, {AttributeName:"SongTitle",AttributeType:"S"} ], KeySchema:[ {AttributeName:"Artist",KeyType:"HASH"}, {AttributeName:"SongTitle",KeyType:"RANGE"} ], ProvisionedThroughput:{ ReadCapacityUnits: 10, WriteCapacityUnits: 10 } } try{ createTableResponse=dynamo.createTable(createTableStruct,{"customResponse": true}) writeOutput("Table created successfully") writeDump(createTableResponse) } catch(any e){ writeDump(e) } // insert an item to the table putItemStruct = { "TableName": "#tableName#", "Item":{ "Artist":{"S":"Beatles"}, "SongTitle":{"S":"Yesterday"}, "Album":{"S":"Some album"} }, "ReturnValues":"NONE" } try{ putItemResponse=dynamo.putItem(putItemStruct,{"hasType": true}) writeOutput("Item inserted successfully in the table.") writeDump(putItemResponse) } catch (any e){ writeDump(e) } // get the item that was inserted getItemStruct={ "TableName": "#tableName#", "Key":{ "Artist":{"S":"Beatles"} } } try{ getItemResponse=dynamo.putItem(getItemStruct) writeOutput("Item retrieved successfully in the table.") writeDump(putItemResponse) } catch (any e){ writeDump(e) } </cfscript>
Update an item in the table
After you've inserted an item in the previous section, you can update the item. In the example below, we have updated the Album to a new value.
<cfscript> cred={ "credentialAlias" : "alias", "vendorName" : "AWS", "region" : "us-east-2", "secretAccessKey" : "secret access", "accessKeyId" : "access key" } conf={ "serviceName"="DYNAMODB" } dynamo=getCloudService(cred, conf) tableName="MusicForAll" // update the item in the table updateItemStruct={ "TableName":"#tableName#", "Key":{ "Artist":{"S":"Beatles"}, "SongTitle":{"S":"Yesterday"} }, "UpdateExpression": "SET Album = :newval", "ExpressionAttributeValues":{ ":newval": {"S": "Some other title"} }, "ReturnValues": "ALL_NEW" } try{ updateItemResponse=dynamo.updateItem(updateItemStruct,{"hasType":true,"customResponse":true}) writeDump(updateItemResponse) } catch(any e){ writeDump(e) } </cfscript>