ddbcli

ddbcli is an interactive command-line client of Amazon DynamoDB.

Gem Version Build Status

Installation

$ gem install ddbcli

If you are not using RubyGems, you can use the script file that depend on only Ruby.

see https://github.com/winebarrel/ddbcli/releases

https://github.com/winebarrel/ddbcli/releases/download/x.x.x/ddbcli-x.x.x.gz
gunzip -c ddbcli-0.x.x.gz > ddbcli
chmod 755 ddbcli

Usage

export AWS_ACCESS_KEY_ID='...'
export AWS_SECRET_ACCESS_KEY='...'
export AWS_REGION=ap-northeast-1

ddbcli -e 'show tables'
#  [
#    "employees"
#  ]

ddbcli # show prompt

Use DynamoDB Local

$ ddbcli --url localhost:8000

Demo

ddbcli demo

GROUP BY (Aggregate)

ap-northeast-1> select all gender from employees
             -> where birth_date begins_with '1960'
             -> | group_by(:gender) {|i| puts "DEBUG: 'i' contains: #{i[0, 3].inspect} ..."\; i.length };
DEBUG: 'i' contains: [{"gender"=>"M"}, {"gender"=>"M"}, {"gender"=>"M"}] ...
DEBUG: 'i' contains: [{"gender"=>"F"}, {"gender"=>"F"}, {"gender"=>"F"}] ...
{
  "M": 546,
  "F": 355
}
// 2 rows in set (0.20 sec)

Use Global Secondary Indexes

Use QueryFilter

Enable ctrl-r (reverse-search-history) on OS X

$ echo 'bind "^R" em-inc-search-prev' >> ~/.editrc

Help

##### Query #####

SHOW TABLES [LIMIT num] [LIKE '...']
  display a table list

SHOW TABLE STATUS [LIKE '...']
  display table statues

SHOW REGIONS
  display a region list

SHOW CREATE TABLE table_name
  display a CREATE TABLE statement

CREATE TABLE table_name (
     key_name {STRING|NUMBER|BINARY} HASH
  [, key_name {STRING|NUMBER|BINARY} RANGE]
  [, INDEX index1_name (attr1 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)}
   , INDEX index2_name (attr2 {STRING|NUMBER|BINARY}) {ALL|KEYS_ONLY|INCLUDE (attr, ...)}
   , ...]
  [, GLOBAL INDEX index1_name (hash_attr1 {STRING|NUMBER|BINARY} [, range_attr1 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num]
   , GLOBAL INDEX index2_name (hash_attr2 {STRING|NUMBER|BINARY} [, range_attr2 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} [READ = num WRITE = num]
   , ...]
) READ = num WRITE = num [STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}]
  create a table

CREATE TABLE table_name LIKE another_table_name [READ = num WRITE = num] [STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}]
  create a table like another table

DROP TABLE table_name [, table_name2, ...]
  delete tables

ALTER TABLE table_name {READ = num WRITE = num|STREAM = {true|false|NEW_IMAGE|OLD_IMAGE|NEW_AND_OLD_IMAGES|KEYS_ONLY}}
  update the provisioned throughput

ALTER TABLE table_name CHANGE GLOBAL INDEX index_name READ = num WRITE = num
  update GSI provisioned throughput

ALTER TABLE table_name ADD GLOBAL INDEX index_name (hash_attr1 {STRING|NUMBER|BINARY} [, range_attr1 {STRING|NUMBER|BINARY}]) {ALL|KEYS_ONLY|INCLUDE (attr, ...)} READ = num WRITE = num
  add GSI

ALTER TABLE table_name DROP GLOBAL INDEX index_name
  delete GSI

GET {*|attr1,attr2,...} FROM table_name WHERE key1 = '...' AND ...
  get items

INSERT INTO table_name (attr1, attr2, ...) VALUES ('val1', 'val2', ...), ('val3', 'val4', ...), ...
INSERT INTO table_name SELECT ...
INSERT INTO table_name SELECT ALL ...
  create items

UPDATE table_name {SET|ADD} attr1 = 'val1', ... WHERE key1 = '...' AND ...
UPDATE ALL table_name {SET|ADD} attr1 = 'val1', ... [WHERE attr1 = '...' AND ...] [LIMIT limit]
  update items
  ("UPDATE" can update only one record. Please use "UPDATE ALL", when you update more than one.)

UPDATE table_name DEL[ETE] attr1, ... WHERE key1 = '...' AND ...
UPDATE ALL table_name DEL[ETE] attr1, ... [WHERE attr1 = '...' AND ...] [LIMIT limit]
  update items (delete attribute)

DELETE FROM table_name WHERE key1 = '...' AND ..
DELETE ALL FROM table_name WHERE [WHERE attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
  delete items
  ("DELETE" can delete only one record. Please use "DELETE ALL", when you update more than one.)

SELECT {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE key1 = '...' AND ...] [HAVING attr1 = '...' AND ...] [ORDER {ASC|DESC}] [LIMIT limit]
SELECT ALL {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE attr1 = '...' AND ...] [LIMIT limit]
SELECT segment/total_segments {*|attr1,attr2,...|COUNT(*)} FROM table_name [USE INDEX (index_name)] [WHERE attr1 = '...' AND ...] [LIMIT limit]
  query using the Query/Scan action
  see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScan.html

DESC[RIBE] table_name
  display information about the table

USE region_or_endpoint
  change an endpoint

NEXT
  display a continuation of a result
  (NEXT statement is published after SELECT statement)


##### Type #####

String
  'London Bridge is...',  "is falling down..." ...

Number
  10, 100, 0.3 ...

Binary
  x'123456789abcd...', x"123456789abcd..." ...

Identifier
  `ABCD...` or Non-keywords

Set
  ('String', 'String', ...), (1, 2, 3, ...)

List
  ['String', (1, 2, 3), {foo: 'FOO', bar: 'BAR'}, ...]

Map
  {key1:'String', "key2":(1, 2, 3), key3: ['FOO', 'BAR'], ...}

Bool
  true, false

Null
  null


##### Operator #####

Query (SELECT)
  = | <= | < | >= | > | BEGINS_WITH | BETWEEN
  see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-KeyConditions

Scan (SELECT ALL), QueryFilter (HAVING)
  = | <> | != | <= | < | >= | > | IS NOT NULL | IS NULL | CONTAINS | NOT CONTAINS | BEGINS_WITH | IN | BETWEEN
  see http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html#DDB-Scan-request-ScanFilter,
      http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-QueryFilter


##### Pass to Ruby/Shell #####

Ryby
  query | ruby_script

  ex) SELECT ALL * FROM employees WHERE gender = 'M' | map {|i| Time.parse(i["birth_date"]) };
      [
        "1957-09-16 00:00:00 +0900",
        "1954-12-16 00:00:00 +0900",
        "1964-05-23 00:00:00 +0900",
        ...

Shell
  query ! shell_command

  ex) SELECT ALL * FROM employees LIMIT 10 ! sort;
      {"birth_date"=>"1957-09-16", "emp_no"=>452020,...
      {"birth_date"=>"1963-07-14", "emp_no"=>16998, ...
      {"birth_date"=>"1964-04-30", "emp_no"=>225407,...
      ...


##### Output to a file #####

Overwrite
  SELECT ALL * FROM employees > 'foo.json';

Append
  SELECT ALL * FROM employees >> 'foo.json';


##### Command #####

.help                           display this message
.quit | .exit                   exit ddbcli
.consistent      (true|false)?  display ConsistentRead parameter or changes it
.iteratable      (true|false)?  display iteratable option or changes it
                                all results are displayed if true
.debug           (true|false)?  display a debug status or changes it
.retry           NUM?           display number of times of a retry or changes it
.retry_interval  SECOND?        display a retry interval second or changes it
.timeout         SECOND?        display a timeout second or changes it
.version                        display a version

Test

# see https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar &
bundle install
bundle exec rake