Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-valued data in DynamoDB using boto

After scouring the documentation and various tutorials, I cannot figure out how to set or update an attribute on a dynamo Item that is a multi-valued data type (number or string set). I'm using boto (boto.dynamodb2, to be specific -- not boto.dynamodb).

Trying something like this (where 'id' is the hash key):

Item(Table('test'), data={'id': '123', 'content': 'test', 'list': [1,2,3,4]}).save()

Results in this error:

TypeError: Unsupported type "<type 'list'>" for value "[1, 2, 3, 4]"

I feel like this must be possible in boto.dynamodb2, but it's odd that I can't find any examples of people doing this. (Everyone is just setting number or string attributes, not number set or string set attributes.)

Any insight on this topic and how I might get this to work with boto would be very much appreciated! I'm guessing I'm overlooking something simple. Thanks!

like image 800
jonsustar Avatar asked Dec 01 '25 09:12

jonsustar


2 Answers

Okay, we were able to figure this out on our own. The problem with my example above is that I'm using a list instead of a set. The value of a multi-value attribute MUST be a set.

For example, this works:

Item(Table('test'), data={'id': '123', 'content': 'test', 'list': set([1,2,3,4])}).save()
like image 102
jonsustar Avatar answered Dec 02 '25 21:12

jonsustar


DnyamoDB now supports Dict/List directly. Boto doesn't have support for it yet, but it's a small patch until it's supported in production.

############################################################
# Patch Dynamizer to support dict/list
############################################################
from boto.dynamodb.types import Dynamizer, get_dynamodb_type

def _get_dynamodb_type(self, attr):
  if isinstance(attr, dict):
    return 'M'
  if isinstance(attr, list):
    return 'L'
  return get_dynamodb_type(attr)

def _encode_m(self, attr):
  result = {}
  for k, v in attr.items():
    result[k] = self.encode(v)
  return result

def _decode_m(self, attr):
  result = {}
  for k, v in attr.items():
    result[k] = self.decode(v)
  return result

def _encode_l(self, attr):
  return [self.encode(v) for v in attr]

def _decode_l(self, attr):
  return [self.decode(v) for v in attr]

Dynamizer._get_dynamodb_type = _get_dynamodb_type
Dynamizer._encode_m = _encode_m
Dynamizer._decode_m = _decode_m
Dynamizer._encode_l = _encode_l
Dynamizer._decode_l = _decode_l
############################################################
# End patch Dynamizer to support dict/list
############################################################
like image 24
Gary Linscott Avatar answered Dec 02 '25 21:12

Gary Linscott



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!