AWS Developer Tools Blog
Amazon DynamoDB Document API in Ruby (Part 1 – Projection Expressions)
Amazon DynamoDB launched JSON Document Support along with several improvements to the DynamoDB API. This post is part of a series where we’ll explore these features in more depth with the AWS SDK for Ruby V2. In particular, this post focuses on putting items into DynamoDB using the Ruby SDK and controlling the data we get back with projection expressions. At the end of the post, we also provide some helpful information for getting started with DynamoDB Local.
Putting JSON data into DynamoDB
DynamoDB now supports the following new data types: Maps, Lists, Booleans, and Nulls. Suppose we have a DynamoDB table for products with a hash key on an “Id” attribute. It’s easy to store such data into DynamoDB with native Ruby types:
# put a JSON item item = { Id: 205, # hash key Title: "20-Bicycle 205", Description: "205 description", BicycleType: "Hybrid", Brand: "Brand-Company C", Price: 500, Gender: "B", Color: Set.new(["Red", "Black"]), ProductCategory: "Bike", InStock: true, QuantityOnHand: nil, NumberSold: BigDecimal.new("1E4"), RelatedItems: [ 341, 472, 649 ], Pictures: { # JSON Map of views to url String FrontView: "http://example.com/products/205_front.jpg", RearView: "http://example.com/products/205_rear.jpg", SideView: "http://example.com/products/205_left_side.jpg", }, ProductReviews: { # JSON Map of stars to List of review Strings FiveStar: [ "Excellent! Can't recommend it highly enough! Buy it!", "Do yourself a favor and buy this." ], OneStar: [ "Terrible product! Do not buy this." ] } } dynamodb.put_item(:table_name => "ProductCatalog", :item => item)
Getting data from DynamoDB using projection expressions
Since DynamoDB now supports more interesting data types, we’ve also added projection expressions and expression attribute names to make it easier to retrieve only the attributes we want:
# get only the attributes we want with projection expressions item = dynamodb.get_item( :table_name => "ProductCatalog", # Get the item with Id == 205 :key => { :Id => 205 }, # for less typing, use expression attribute names to substitute # "ProductReviews" with "#pr" and "RelatedItems" with "#ri" :expression_attribute_names => { "#pr" => "ProductReviews", "#ri" => "RelatedItems", }, # get Price, Color, FiveStar reviews, 0th and 2nd related items :projection_expression => "Price, Color, #pr.FiveStar, #ri[0], #ri[2], #pr.NoStar, #ri[4]" # try projecting non-existent attributes too ).data.item puts item["Price"].to_i # 500 puts item["Color"].inspect # #<Set: {"Black", "Red"}> puts item["ProductReviews"]["FiveStar"][0] # Excellent! Can't recommend it highly enough! Buy it! puts item["ProductReviews"]["FiveStar"][1] # Do yourself a favor and buy this. puts item["ProductReviews"]["OneStar"].inspect # nil (because we only projected FiveStar reviews) puts item["ProductReviews"]["NoStar"].inspect # nil (because no NoStar reviews) puts item["RelatedItems"] # 0.341E3 (0th element) # 0.649E3 (2nd element) puts item["RelatedItems"].size # 2 (non-existent 4th element not present)
Next Steps
As you can see, it’s easy to put and get items in DynamoDB with the AWS SDK for Ruby. In upcoming blog posts, we’ll take a closer look at expressions for filtering and updating data.
Feel free to get started on DynamoDB Local with the following code (note that it uses the credentials file approach for specifying AWS credentials):
#! /usr/bin/ruby require "set" require "bigdecimal" require "aws-sdk-core" # Configure SDK # use credentials file at .aws/credentials Aws.config[:credentials] = Aws::SharedCredentials.new Aws.config[:region] = "us-west-2" # point to DynamoDB Local, comment out this line to use real DynamoDB Aws.config[:dynamodb] = { endpoint: "http://localhost:8000" } dynamodb = Aws::DynamoDB::Client.new ## Create the table if it doesn't exist begin dynamodb.describe_table(:table_name => "ProductCatalog") rescue Aws::DynamoDB::Errors::ResourceNotFoundException dynamodb.create_table( :table_name => "ProductCatalog", :attribute_definitions => [ { :attribute_name => :Id, :attribute_type => :N } ], :key_schema => [ { :attribute_name => :Id, :key_type => :HASH } ], :provisioned_throughput => { :read_capacity_units => 1, :write_capacity_units => 1, } ) # wait for table to be created puts "waiting for table to be created..." dynamodb.wait_until(:table_exists, table_name: "ProductCatalog") puts "table created!" end