€cdocutils.nodes document q)�q}q(U nametypesq}q(X/an introduction to boto's dynamodb v2 interfaceqNXusing an existing tableqNXqueryingqNXdeleting an itemq NXdeleting a tableq NXupdating an itemq NX batch writingq NX parallel scanq NXdynamodbqˆX next stepsqNX getting an item & accessing dataqNXiterator protocolqˆXcreating a new itemqNX batch readingqNXamazon dynamodb localqˆX dynamodb2_tutqˆXcreating a new tableqNXdynamodb localqNXthe high-level apiqNX the resultsetqNuUsubstitution_defsq}qUparse_messagesq]qUcurrent_sourceqNU decorationqNUautofootnote_startq KUnameidsq!}q"(hU/an-introduction-to-boto-s-dynamodb-v2-interfaceq#hUusing-an-existing-tableq$hUqueryingq%h Udeleting-an-itemq&h Udeleting-a-tableq'h Uupdating-an-itemq(h U batch-writingq)h U parallel-scanq*hUdynamodbq+hU next-stepsq,hUgetting-an-item-accessing-dataq-hUiterator-protocolq.hUcreating-a-new-itemq/hU batch-readingq0hUamazon-dynamodb-localq1hU dynamodb2-tutq2hUcreating-a-new-tableq3hUdynamodb-localq4hUthe-high-level-apiq5hU the-resultsetq6uUchildrenq7]q8(cdocutils.nodes target q9)�q:}q;(U rawsourceqXC/Users/kyleknap/Documents/GitHub/boto/docs/source/dynamodb2_tut.rstq?Utagnameq@UtargetqAU attributesqB}qC(UidsqD]UbackrefsqE]UdupnamesqF]UclassesqG]UnamesqH]UrefidqIh2uUlineqJKUdocumentqKhh7]ubcdocutils.nodes section qL)�qM}qN(hh?Uexpect_referenced_by_nameqO}qPhh:sh@UsectionqQhB}qR(hF]hG]hE]hD]qS(h#h2ehH]qT(hheuhJKhKhUexpect_referenced_by_idqU}qVh2h:sh7]qW(cdocutils.nodes title qX)�qY}qZ(hh?h@Utitleq\hB}q](hF]hG]hE]hD]hH]uhJKhKhh7]q^cdocutils.nodes Text q_X/An Introduction to boto's DynamoDB v2 interfaceq`…�qa}qb(hh?h@U paragraphqfhB}qg(hF]hG]hE]hD]hH]uhJKhKhh7]qh(h_X4This tutorial focuses on the boto interface to AWS' qi…�qj}qk(hh?h@hAhB}q~(hrhshD]qh+ahE]hF]hG]hH]q€hauhJK hKhh7]ubcdocutils.nodes warning q�)�q‚}qƒ(h`.h=hMh>h?h@Uwarningq„hB}q…(hF]hG]hE]hD]hH]uhJNhKhh7]q†hc)�q‡}qˆ(h`.h=h‚h>h?h@hfhB}q‰(hF]hG]hE]hD]hH]uhJKh7]qŠ(h_XThis tutorial covers the q‹…�qŒ}q�(h`q�h=h‡h>h?h@U pending_xrefqžhB}qŸ(UreftypeXdocq Urefwarnq¡ˆU reftargetq¢X dynamodb_tutU refdomainUhD]hE]U refexplicitˆhF]hG]hH]Urefdocq£X dynamodb2_tutq¤uhJKh7]q¥cdocutils.nodes literal q¦)�q§}q¨(hh?h@hfhB}qµ(hF]hG]hE]hD]hH]uhJKhKhh7]q¶(h_XoThe v2 DynamoDB API has both a high-level & low-level component. The low-level API (contained primarily within q·…�q¸}q¹(hh?h@hfhB}qÇ(hF]hG]hE]hD]hH]uhJKhKhh7]qÈh_X~The high-level API attempts to make interacting with the service more natural from Python. It supports most of the featureset.qÉ…�qÊ}qË(hh?h@hQhB}qÎ(hF]hG]hE]hD]qÏh5ahH]qÐhauhJKhKhh7]qÑ(hX)�qÒ}qÓ(hh?h@h\hB}qÕ(hF]hG]hE]hD]hH]uhJKhKhh7]qÖh_XThe High-Level APIq×…�qØ}qÙ(hh?h@hfhB}qÜ(hF]hG]hE]hD]hH]uhJKhKhh7]qÝ(h_X<Most of the interaction centers around a single object, the qÞ…�qß}qà(hh?h@hQhB}qí(hF]hG]hE]hD]qîh3ahH]qïhauhJK%hKhh7]qð(hX)�qñ}qò(hh?h@h\hB}qô(hF]hG]hE]hD]hH]uhJK%hKhh7]qõh_XCreating a New Tableqö…�q÷}qø(hh?h@hfhB}qû(hF]hG]hE]hD]hH]uhJK'hKhh7]qü(h_X(To create a new table, you need to call qý…�qþ}qÿ(hh?h@hfhB}r (hF]hG]hE]hD]hH]uhJK*hKhh7]rh_X/Since both the key schema and local secondary indexes can not be modified after the table is created, you'll need to plan ahead of time how you think the table will be used. Both the keys & indexes are also used for querying, so you'll want to represent the data you'll need when querying there as well.r…�r}r(hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJK0hKhh7]r(h_X-For the schema, you can either have a single r…�r}r(h…�r?}r@(hh?h@hfhB}rW(hF]hG]hE]hD]hH]uhJK8hKhh7]rX(h_X8For the local secondary indexes, you can choose from an rY…�rZ}r[(h duplicates only the keys from the schema onto the index. The r‹…�rŒ}r�(h duplicates only the keys from the schema onto the index. The h=jUubh¦)�rŽ}r�(hh?h@hfhB}r›(hF]hG]hE]hD]hH]uhJK?hKhh7]rœh_XSimple example:r�…�rž}rŸ(h>> from boto.dynamodb2.fields import HashKey >>> from boto.dynamodb2.table import Table # Uses your ``aws_access_key_id`` & ``aws_secret_access_key`` from either a # config file or environment variable & the default region. >>> users = Table.create('users', schema=[ ... HashKey('username'), ... ])h=hëh>h?h@U literal_blockr£hB}r¤(U xml:spacer¥Upreserver¦hD]hE]hF]hG]hH]uhJKAhKhh7]r§h_X0>>> from boto.dynamodb2.fields import HashKey >>> from boto.dynamodb2.table import Table # Uses your ``aws_access_key_id`` & ``aws_secret_access_key`` from either a # config file or environment variable & the default region. >>> users = Table.create('users', schema=[ ... HashKey('username'), ... ])r¨…�r©}rª(hh?h@hfhB}r®(hF]hG]hE]hD]hH]uhJKJhKhh7]r¯h_XA full example:r°…�r±}r²(h>> import boto.dynamodb2 >>> from boto.dynamodb2.fields import HashKey, RangeKey, KeysOnlyIndex, AllIndex >>> from boto.dynamodb2.table import Table >>> from boto.dynamodb2.types import NUMBER >>> users = Table.create('users', schema=[ ... HashKey('account_type', data_type=NUMBER), ... RangeKey('last_name'), ... ], throughput={ ... 'read': 5, ... 'write': 15, ... }, indexes=[ ... AllIndex('EverythingIndex', parts=[ ... HashKey('account_type', data_type=NUMBER), ... ]) ... ], ... # If you need to specify custom parameters like keys or region info... ... connection= boto.dynamodb2.connect_to_region('us-east-1'))h=hëh>h?h@j£hB}rµ(j¥j¦hD]hE]hF]hG]hH]uhJKLhKhh7]r¶h_X‹>>> import boto.dynamodb2 >>> from boto.dynamodb2.fields import HashKey, RangeKey, KeysOnlyIndex, AllIndex >>> from boto.dynamodb2.table import Table >>> from boto.dynamodb2.types import NUMBER >>> users = Table.create('users', schema=[ ... HashKey('account_type', data_type=NUMBER), ... RangeKey('last_name'), ... ], throughput={ ... 'read': 5, ... 'write': 15, ... }, indexes=[ ... AllIndex('EverythingIndex', parts=[ ... HashKey('account_type', data_type=NUMBER), ... ]) ... ], ... # If you need to specify custom parameters like keys or region info... ... connection= boto.dynamodb2.connect_to_region('us-east-1'))r·…�r¸}r¹(hh?h@hQhB}r¼(hF]hG]hE]hD]r½h$ahH]r¾hauhJKahKhh7]r¿(hX)�rÀ}rÁ(hh?h@h\hB}rÃ(hF]hG]hE]hD]hH]uhJKahKhh7]rÄh_XUsing an Existing TablerÅ…�rÆ}rÇ(hh?h@hfhB}rÊ(hF]hG]hE]hD]hH]uhJKchKhh7]rË(h_X^Once a table has been created, using it is relatively simple. You can either specify just the rÌ…�rÍ}rÎ(hh?h@hfhB}rð(hF]hG]hE]hD]hH]uhJKhhKhh7]rñh_X Lazy example:rò…�ró}rô(h>> from boto.dynamodb2.table import Table >>> users = Table('users')h=jºh>h?h@j£hB}r÷(j¥j¦hD]hE]hF]hG]hH]uhJKjhKhh7]røh_XE>>> from boto.dynamodb2.table import Table >>> users = Table('users')rù…�rú}rû(hh?h@hfhB}rÿ(hF]hG]hE]hD]hH]uhJKmhKhh7]rh_XEfficient example:r…�r}r(h>> from boto.dynamodb2.fields import HashKey, RangeKey, AllIndex >>> from boto.dynamodb2.table import Table >>> from boto.dynamodb2.types import NUMBER >>> users = Table('users', schema=[ ... HashKey('account_type', data_type=NUMBER), ... RangeKey('last_name'), ... ], indexes=[ ... AllIndex('EverythingIndex', parts=[ ... HashKey('account_type', data_type=NUMBER), ... ]) ... ])h=jºh>h?h@j£hB}r(j¥j¦hD]hE]hF]hG]hH]uhJKohKhh7]rh_X”>>> from boto.dynamodb2.fields import HashKey, RangeKey, AllIndex >>> from boto.dynamodb2.table import Table >>> from boto.dynamodb2.types import NUMBER >>> users = Table('users', schema=[ ... HashKey('account_type', data_type=NUMBER), ... RangeKey('last_name'), ... ], indexes=[ ... AllIndex('EverythingIndex', parts=[ ... HashKey('account_type', data_type=NUMBER), ... ]) ... ])r…�r }r (hh?h@hQhB}r (hF]hG]hE]hD]rh/ahH]rhauhJK}hKhh7]r(hX)�r}r(hh?h@h\hB}r(hF]hG]hE]hD]hH]uhJK}hKhh7]rh_XCreating a New Itemr…�r}r(hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJKhKhh7]r(h_XOnce you have a r…�r}r(hh?h@hfhB}r,(hF]hG]hE]hD]hH]uhJK‚hKhh7]r-(h_XThe first is to use the r.…�r/}r0(hh_Xmustr?…�r@}rA(hh?h@hfhB}rQ(hF]hG]hE]hD]hH]uhJK‡hKhh7]rRh_XExample:rS…�rT}rU(h>> from boto.dynamodb2.table import Table >>> users = Table('users') # Create the new user. >>> users.put_item(data={ ... 'username': 'johndoe', ... 'first_name': 'John', ... 'last_name': 'Doe', ... }) Trueh=j h>h?h@j£hB}rX(j¥j¦hD]hE]hF]hG]hH]uhJK‰hKhh7]rYh_XÜ>>> from boto.dynamodb2.table import Table >>> users = Table('users') # Create the new user. >>> users.put_item(data={ ... 'username': 'johndoe', ... 'first_name': 'John', ... 'last_name': 'Doe', ... }) TruerZ…�r[}r\(hh?h@hfhB}r_(hF]hG]hE]hD]hH]uhJK”hKhh7]r`(h_X,The alternative is to manually construct an ra…�rb}rc(hh?h@hfhB}r{(hF]hG]hE]hD]hH]uhJK˜hKhh7]r|h_XExample:r}…�r~}r(h>> from boto.dynamodb2.items import Item >>> from boto.dynamodb2.table import Table >>> users = Table('users') # WARNING - This doens't save it yet! >>> johndoe = Item(users, data={ ... 'username': 'johndoe', ... 'first_name': 'John', ... 'last_name': 'Doe', ... }) # The data now gets persisted to the server. >>> johndoe.save() Trueh=j h>h?h@j£hB}r‚(j¥j¦hD]hE]hF]hG]hH]uhJKšhKhh7]rƒh_X\>>> from boto.dynamodb2.items import Item >>> from boto.dynamodb2.table import Table >>> users = Table('users') # WARNING - This doens't save it yet! >>> johndoe = Item(users, data={ ... 'username': 'johndoe', ... 'first_name': 'John', ... 'last_name': 'Doe', ... }) # The data now gets persisted to the server. >>> johndoe.save() Truer„…�r…}r†(hh?h@hQhB}r‰(hF]hG]hE]hD]rŠh-ahH]r‹hauhJKªhKhh7]rŒ(hX)�r�}rŽ(hh?h@h\hB}r�(hF]hG]hE]hD]hH]uhJKªhKhh7]r‘h_X Getting an Item & Accessing Datar’…�r“}r”(hh?h@hfhB}r—(hF]hG]hE]hD]hH]uhJK¬hKhh7]r˜(h_X}With data now in DynamoDB, if you know the key of the item, you can fetch it back out. Specify the key value(s) as kwargs to r™…�rš}r›(hh?h@hfhB}r¨(hF]hG]hE]hD]hH]uhJK¯hKhh7]r©h_XExample:rª…�r«}r¬(h>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> johndoe = users.get_item(username='johndoe')h=j‡h>h?h@j£hB}r¯(j¥j¦hD]hE]hF]hG]hH]uhJK±hKhh7]r°h_Xw>>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> johndoe = users.get_item(username='johndoe')r±…�r²}r³(hh?h@hfhB}r¶(hF]hG]hE]hD]hH]uhJK¶hKhh7]r·(h_XOnce you have an r¸…�r¹}rº(h>> johndoe = users.get_item(username='johndoe') # Read a field out. >>> johndoe['first_name'] 'John' # Change a field (DOESN'T SAVE YET!). >>> johndoe['first_name'] = 'Johann' # Delete data from it (DOESN'T SAVE YET!). >>> del johndoe['last_name']h=j‡h>h?h@j£hB}rÇ(j¥j¦hD]hE]hF]hG]hH]uhJK¹hKhh7]rÈh_Xû>>> johndoe = users.get_item(username='johndoe') # Read a field out. >>> johndoe['first_name'] 'John' # Change a field (DOESN'T SAVE YET!). >>> johndoe['first_name'] = 'Johann' # Delete data from it (DOESN'T SAVE YET!). >>> del johndoe['last_name']rÉ…�rÊ}rË(hh?h@hQhB}rÎ(hF]hG]hE]hD]rÏh(ahH]rÐh auhJKÇhKhh7]rÑ(hX)�rÒ}rÓ(hh?h@h\hB}rÕ(hF]hG]hE]hD]hH]uhJKÇhKhh7]rÖh_XUpdating an Itemr×…�rØ}rÙ(hh?h@hfhB}rÜ(hF]hG]hE]hD]hH]uhJKÉhKhh7]rÝ(h_XFJust creating new items or changing only the in-memory version of the rÞ…�rß}rà(hh?h@hfhB}rí(hF]hG]hE]hD]hH]uhJKÍhKhh7]rîh_X÷The first is sending all the data with the expectation nothing has changed since you read the data. DynamoDB will verify the data is in the original state and, if so, will send all of the item's data. If that expectation fails, the call will fail:rï…�rð}rñ(h>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Affects all fields, even the ones not changed locally. >>> johndoe.save() Trueh=jÌh>h?h@j£hB}rô(j¥j¦hD]hE]hF]hG]hH]uhJKÒhKhh7]rõh_X>>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Affects all fields, even the ones not changed locally. >>> johndoe.save() Truerö…�r÷}rø(hh?h@hfhB}rû(hF]hG]hE]hD]hH]uhJKÛhKhh7]rüh_XŽThe second is a full overwrite. If you can be confident your version of the data is the most correct, you can force an overwrite of the data.:rý…�rþ}rÿ(h>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Specify ``overwrite=True`` to fully replace the data. >>> johndoe.save(overwrite=True) Trueh=jÌh>h?h@j£hB}r(j¥j¦hD]hE]hF]hG]hH]uhJKÞhKhh7]rh_X>>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Specify ``overwrite=True`` to fully replace the data. >>> johndoe.save(overwrite=True) Truer…�r}r(hh?h@hfhB}r (hF]hG]hE]hD]hH]uhJKçhKhh7]r h_XÀThe last is a partial update. If you've only modified certain fields, you can send a partial update that only writes those fields, allowing other (potentially changed) fields to go untouched.:r …�r }r (h>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Partial update, only sending/affecting the # ``first_name/whatever/last_name`` fields. >>> johndoe.partial_save() Trueh=jÌh>h?h@j£hB}r(j¥j¦hD]hE]hF]hG]hH]uhJKëhKhh7]rh_X+>>> johndoe = users.get_item(username='johndoe') >>> johndoe['first_name'] = 'Johann' >>> johndoe['whatever'] = "man, that's just like your opinion" >>> del johndoe['last_name'] # Partial update, only sending/affecting the # ``first_name/whatever/last_name`` fields. >>> johndoe.partial_save() Truer…�r}r(hh?h@hQhB}r(hF]hG]hE]hD]rh&ahH]rh auhJK÷hKhh7]r(hX)�r}r(hh?h@h\hB}r(hF]hG]hE]hD]hH]uhJK÷hKhh7]rh_XDeleting an Itemr …�r!}r"(hh?h@hfhB}r&(hF]hG]hE]hD]hH]uhJKùhKhh7]r'h_XhYou can also delete items from the table. You have two choices, depending on what data you have present.r(…�r)}r*(hh?h@hfhB}r-(hF]hG]hE]hD]hH]uhJKühKhh7]r.(h_XIf you already have an r/…�r0}r1(h(hF]hG]hE]hD]hH]uh=j+h7]r?h_X Item.deleter@…�rA}rB(h>> johndoe.delete() Trueh=jh>h?h@j£hB}rH(j¥j¦hD]hE]hF]hG]hH]uhJKÿhKhh7]rIh_X>>> johndoe.delete() TruerJ…�rK}rL(hh?h@hfhB}rO(hF]hG]hE]hD]hH]uhJMhKhh7]rP(h_XIf you don't have an rQ…�rR}rS(h>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> users.delete_item(username='johndoe') Trueh=jh>h?h@j£hB}rt(j¥j¦hD]hE]hF]hG]hH]uhJMhKhh7]ruh_Xu>>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> users.delete_item(username='johndoe') Truerv…�rw}rx(hh?h@hQhB}r{(hF]hG]hE]hD]r|h)ahH]r}h auhJM hKhh7]r~(hX)�r}r€(hh?h@h\hB}r‚(hF]hG]hE]hD]hH]uhJM hKhh7]rƒh_X Batch Writingr„…�r…}r†(hh?h@hfhB}rŠ(hF]hG]hE]hD]hH]uhJMhKhh7]r‹h_XŸIf you're loading a lot of data at a time, making use of batch writing can both speed up the process & reduce the number of write requests made to the service.rŒ…�r�}rŽ(hh?h@hfhB}r‘(hF]hG]hE]hD]hH]uhJMhKhh7]r’(h_XrBatch writing involves wrapping the calls you want batched in a context manager. The context manager imitates the r“…�r”}r•(h>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> with users.batch_write() as batch: ... batch.put_item(data={ ... 'username': 'anotherdoe', ... 'first_name': 'Another', ... 'last_name': 'Doe', ... 'date_joined': int(time.time()), ... }) ... batch.put_item(data={ ... 'username': 'alice', ... 'first_name': 'Alice', ... 'date_joined': int(time.time()), ... }) ... batch.delete_item(username=jane')h=jyh>h?h@j£hB}r¬(j¥j¦hD]hE]hF]hG]hH]uhJMhKhh7]r­h_Xò>>> from boto.dynamodb2.table import Table >>> users = Table('users') >>> with users.batch_write() as batch: ... batch.put_item(data={ ... 'username': 'anotherdoe', ... 'first_name': 'Another', ... 'last_name': 'Doe', ... 'date_joined': int(time.time()), ... }) ... batch.put_item(data={ ... 'username': 'alice', ... 'first_name': 'Alice', ... 'date_joined': int(time.time()), ... }) ... batch.delete_item(username=jane')r®…�r¯}r°(hh?h@hfhB}r´(hF]hG]hE]hD]hH]uhJM(hKhh7]rµh_XRHowever, there are some limitations on what you can do within the context manager.r¶…�r·}r¸(hh?h@U bullet_listr¼hB}r½(Ubulletr¾X*hD]hE]hF]hG]hH]uhJM+hKhh7]r¿(cdocutils.nodes list_item rÀ)�rÁ}rÂ(hh?h@U list_itemrÄhB}rÅ(hF]hG]hE]hD]hH]uhJNhKhh7]rÆhc)�rÇ}rÈ(hh?h@hfhB}rÉ(hF]hG]hE]hD]hH]uhJM+h7]rÊh_X;It can't read data at all or do batch any other operations.rË…�rÌ}rÍ(hh?h@jÄhB}rÐ(hF]hG]hE]hD]hH]uhJNhKhh7]rÑhc)�rÒ}rÓ(hh?h@hfhB}rÕ(hF]hG]hE]hD]hH]uhJM,h7]rÖh_X<You can't put & delete the same data within a batch request.r×…�rØ}rÙ(hh?h@UnoterÝhB}rÞ(hF]hG]hE]hD]hH]uhJNhKhh7]rßhc)�rà}rá(hh?h@hfhB}râ(hF]hG]hE]hD]hH]uhJM0h7]rã(h_XÔAdditionally, the context manager can only batch 25 items at a time for a request (this is a DynamoDB limitation). It is handled for you so you can keep writing additional items, but you should be aware that 100 rä…�rå}ræ(hh?h@hQhB}ró(hF]hG]hE]hD]rôh%ahH]rõhauhJM7hKhh7]rö(hX)�r÷}rø(hh?h@h\hB}rú(hF]hG]hE]hD]hH]uhJM7hKhh7]rûh_XQueryingrü…�rý}rþ(hh?h@h„hB}r(hF]hG]hE]hD]hH]uhJNhKhh7]rhc)�r}r(hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJM;h7]r(h_XThe r…�r}r (hh=jñh>h?h@hfhB}r?(hF]hG]hE]hD]hH]uhJM@hKhh7]r@h_XÔManually fetching out each item by itself isn't tenable for large datasets. To cope with fetching many records, you can either perform a standard query, query via a local secondary index or scan the entire table.rA…�rB}rC(hh=j<ubaubhc)�rD}rE(hh?h@hfhB}rF(hF]hG]hE]hD]hH]uhJMDhKhh7]rG(h_XyA standard query typically gets run against a hash+range key combination. Filter parameters are passed as kwargs & use a rH…�rI}rJ(hh?h@hfhB}rW(hF]hG]hE]hD]hH]uhJMHhKhh7]rXh_X…In terms of querying, our original schema is less than optimal. For the following examples, we'll be using the following table setup:rY…�rZ}r[(h>> users = Table.create('users', schema=[ ... HashKey('account_type'), ... RangeKey('last_name'), ... ], indexes=[ ... AllIndex('DateJoinedIndex', parts=[ ... HashKey('account_type'), ... RangeKey('date_joined', data_type=NUMBER), ... ]), ... ])h=jñh>h?h@j£hB}r^(j¥j¦hD]hE]hF]hG]hH]uhJMKhKhh7]r_h_X>>> users = Table.create('users', schema=[ ... HashKey('account_type'), ... RangeKey('last_name'), ... ], indexes=[ ... AllIndex('DateJoinedIndex', parts=[ ... HashKey('account_type'), ... RangeKey('date_joined', data_type=NUMBER), ... ]), ... ])r`…�ra}rb(hh?h@hfhB}rf(hF]hG]hE]hD]hH]uhJMUhKhh7]rgh_XôWhen executing the query, you get an iterable back that contains your results. These results may be spread over multiple requests as DynamoDB paginates them. This is done transparently, but you should be aware it may take more than one request.rh…�ri}rj(hh?h@hfhB}rn(hF]hG]hE]hD]hH]uhJMZhKhh7]roh_X;To run a query for last names starting with the letter "D":rp…�rq}rr(h>> names_with_d = users.query_2( ... account_type__eq='standard_user', ... last_name__beginswith='D' ... ) >>> for user in names_with_d: ... print user['first_name'] 'Bob' 'Jane' 'John'h=jñh>h?h@j£hB}ru(j¥j¦hD]hE]hF]hG]hH]uhJM\hKhh7]rvh_XÇ>>> names_with_d = users.query_2( ... account_type__eq='standard_user', ... last_name__beginswith='D' ... ) >>> for user in names_with_d: ... print user['first_name'] 'Bob' 'Jane' 'John'rw…�rx}ry(hh?h@hfhB}r|(hF]hG]hE]hD]hH]uhJMghKhh7]r}(h_XYou can also reverse results (r~…�r}r€(h>> rev_with_d = users.query_2( ... account_type__eq='standard_user', ... last_name__beginswith='D', ... reverse=True, ... limit=2 ... ) >>> for user in rev_with_d: ... print user['first_name'] 'John' 'Jane'h=jñh>h?h@j£hB}r—(j¥j¦hD]hE]hF]hG]hH]uhJMjhKhh7]r˜h_Xä>>> rev_with_d = users.query_2( ... account_type__eq='standard_user', ... last_name__beginswith='D', ... reverse=True, ... limit=2 ... ) >>> for user in rev_with_d: ... print user['first_name'] 'John' 'Jane'r™…�rš}r›(hh?h@hfhB}rž(hF]hG]hE]hD]hH]uhJMvhKhh7]rŸ(h_X]You can also run queries against the local secondary indexes. Simply provide the index name (r …�r¡}r¢(h>> recent = users.query_2( ... account_type__eq='standard_user', ... date_joined__gte=time.time() - (60 * 60), ... index='DateJoinedIndex' ... ) >>> for user in recent: ... print user['first_name'] 'Alice' 'Jane'h=jñh>h?h@j£hB}r¯(j¥j¦hD]hE]hF]hG]hH]uhJMzhKhh7]r°h_X# Users within the last hour. >>> recent = users.query_2( ... account_type__eq='standard_user', ... date_joined__gte=time.time() - (60 * 60), ... index='DateJoinedIndex' ... ) >>> for user in recent: ... print user['first_name'] 'Alice' 'Jane'r±…�r²}r³(hh?h@hfhB}r¶(hF]hG]hE]hD]hH]uhJM†hKhh7]r·(h_XÀBy default, DynamoDB can return a large amount of data per-request (up to 1Mb of data). To prevent these requests from drowning other smaller gets, you can specify a smaller page size via the r¸…�r¹}rº(h>> all_users = users.query_2( ... account_type__eq='standard_user', ... date_joined__gte=0, ... max_page_size=10 ... ) # Usage is the same, but now many smaller requests are done. >>> for user in recent: ... print user['first_name'] 'Alice' 'Jane'h=jñh>h?h@j£hB}rÛ(j¥j¦hD]hE]hF]hG]hH]uhJM‹hKhh7]rÜh_X]# Small pages yield faster responses & less potential of drowning other # requests. >>> all_users = users.query_2( ... account_type__eq='standard_user', ... date_joined__gte=0, ... max_page_size=10 ... ) # Usage is the same, but now many smaller requests are done. >>> for user in recent: ... print user['first_name'] 'Alice' 'Jane'rÝ…�rÞ}rß(hh?h@hfhB}râ(hF]hG]hE]hD]hH]uhJM™hKhh7]rã(h_X_Finally, if you need to query on data that's not in either a key or in an index, you can run a rä…�rå}ræ(hh?h@h„hB}ró(hF]hG]hE]hD]hH]uhJNhKhh7]rôhc)�rõ}rö(hh?h@hfhB}rø(hF]hG]hE]hD]hH]uhJM h7]rùh_XŽScans are consistent & run over the entire table, so relatively speaking, they're more expensive than plain queries or queries against an LSI.rú…�rû}rü(hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJM£hKhh7]rh_X7An example scan of all records in the table looks like:r…�r}r(h>> all_users = users.scan()h=jñh>h?h@j£hB}r(j¥j¦hD]hE]hF]hG]hH]uhJM¥hKhh7]rh_X>>> all_users = users.scan()r …�r }r (hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJM§hKhh7]rh_XFiltering a scan looks like:r…�r}r(h>> owners_with_emails = users.scan( ... is_owner__eq=1, ... email__null=False, ... ) >>> for user in recent: ... print user['first_name'] 'George' 'John'h=jñh>h?h@j£hB}r(j¥j¦hD]hE]hF]hG]hH]uhJM©hKhh7]rh_X§>>> owners_with_emails = users.scan( ... is_owner__eq=1, ... email__null=False, ... ) >>> for user in recent: ... print user['first_name'] 'George' 'John'r…�r}r(hh?h@hQhB}r(hF]hG]hE]hD]rh6ahH]rhauhJMµhKhh7]r (hX)�r!}r"(hh?h@h\hB}r$(hF]hG]hE]hD]hH]uhJMµhKhh7]r%(h_XThe r&…�r'}r((hh?h@hfhB}r4(hF]hG]hE]hD]hH]uhJM·hKhh7]r5(h_XBoth r6…�r7}r8(h}r?(hh?h@hfhB}re(hF]hG]hE]hD]hH]uhJM»hKhh7]rf(h_X!Typical use is simply a standard rg…�rh}ri(h>> result_set = users.scan() >>> for user in result_set: ... print user['first_name']h=jh>h?h@j£hB}rv(j¥j¦hD]hE]hF]hG]hH]uhJM½hKhh7]rwh_XZ>>> result_set = users.scan() >>> for user in result_set: ... print user['first_name']rx…�ry}rz(hh?h@hfhB}r}(hF]hG]hE]hD]hH]uhJMÁhKhh7]r~(h_XbHowever, this throws away results as it fetches more data. As a result, you can't index it like a r…�r€}r�(h>> len(result_set) 0h=jh>Nh@U doctest_blockrŽhB}r�(j¥j¦hD]hE]hF]hG]hH]uhJNhKhh7]r�h_X>>> len(result_set) 0r‘…�r’}r“(hh?h@hfhB}r–(hF]hG]hE]hD]hH]uhJMÇhKhh7]r—(h_X§Because it does this, if you need to loop over your results more than once (or do things like negative indexing, length checks, etc.), you should wrap it in a call to r˜…�r™}rš(h>> result_set = users.scan() >>> all_users = list(result_set) # Slice it for every other user. >>> for user in all_users[::2]: ... print user['first_name']h=jh>h?h@j£hB}r§(j¥j¦hD]hE]hF]hG]hH]uhJMËhKhh7]r¨h_X >>> result_set = users.scan() >>> all_users = list(result_set) # Slice it for every other user. >>> for user in all_users[::2]: ... print user['first_name']r©…�rª}r«(hh?h@h„hB}r®(hF]hG]hE]hD]hH]uhJNhKhh7]r¯(hc)�r°}r±(hh?h@hfhB}r²(hF]hG]hE]hD]hH]uhJMÓh7]r³(h_X!Wrapping calls like the above in r´…�rµ}r¶(hh?h@hfhB}rÖ(hF]hG]hE]hD]hH]uhJMÖh7]r×(h_XAppropriate use of the rØ…�rÙ}rÚ(hh?h@hfhB}r(hF]hG]hE]hD]hH]uhJMÙh7]r(h_X2Alternatively, you can build your own list, using r…�r}r (hh?h@hAhB}r (hrjZhD]r!h.ahE]hF]hG]hH]r"hauhJMÜhKhh7]ubeubeubhL)�r#}r$(hh?h@hQhB}r%(hF]hG]hE]hD]r&h*ahH]r'h auhJMàhKhh7]r((hX)�r)}r*(hh?h@h\hB}r,(hF]hG]hE]hD]hH]uhJMàhKhh7]r-h_X Parallel Scanr.…�r/}r0(hh?h@hfhB}r3(hF]hG]hE]hD]hH]uhJMâhKhh7]r4(h_XYDynamoDB also includes a feature called "Parallel Scan", which allows you to make use of r5…�r6}r7(h(hh?h@hfhB}rE(hF]hG]hE]hD]hH]uhJMæhKhh7]rFh_XÏThis does require extra code on the user's part & you should ensure that you need the speed boost, have enough data to justify it and have the extra capacity to read it without impacting other queries/scans.rG…�rH}rI(hTo run it, you should pick the ``total_segments`` to use, which is an integer representing the number of temporary partitions you'd divide your table into. You then need to spin up a thread/process for each one, giving each thread/process a ``segment``, which is a zero-based integer of the segment you'd like to scan.h=j#h>h?h@hfhB}rL(hF]hG]hE]hD]hH]uhJMêhKhh7]rM(h_XTo run it, you should pick the rN…�rO}rP(hh?h@hfhB}rg(hF]hG]hE]hD]hH]uhJMðhKhh7]rhh_X[An example of using parallel scan to send out email to all users might look something like:ri…�rj}rk(hh?h@j£hB}rn(j¥j¦hD]hE]hF]hG]hH]uhJMóhKhh7]roh_XÐ#!/usr/bin/env python import threading import boto.ses import boto.dynamodb2 from boto.dynamodb2.table import Table AWS_ACCESS_KEY_ID = '' AWS_SECRET_ACCESS_KEY = '' APPROVED_EMAIL = 'some@address.com' def send_email(email): # Using Amazon's Simple Email Service, send an email to a given # email address. You must already have an email you've verified with # AWS before this will work. conn = boto.ses.connect_to_region( 'us-east-1', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY ) conn.send_email( APPROVED_EMAIL, "[OurSite] New feature alert!", "We've got some exciting news! We added a new feature to...", [email] ) def process_segment(segment=0, total_segments=10): # This method/function is executed in each thread, each getting its # own segment to process through. conn = boto.dynamodb2.connect_to_region( 'us-east-1', aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY ) table = Table('users', connection=conn) # We pass in the segment & total_segments to scan here. for user in table.scan(segment=segment, total_segments=total_segments): send_email(user['email']) def send_all_emails(): pool = [] # We're choosing to divide the table in 3, then... pool_size = 3 # ...spinning up a thread for each segment. for i in range(pool_size): worker = threading.Thread( target=process_segment, kwargs={ 'segment': i, 'total_segments': pool_size, } ) pool.append(worker) # We start them to let them start scanning & consuming their # assigned segment. worker.start() # Finally, we wait for each to finish. for thread in pool: thread.join() if __name__ == '__main__': send_all_emails()rp…�rq}rr(hh?h@hQhB}ru(hF]hG]hE]hD]rvh0ahH]rwhauhJM=hKhh7]rx(hX)�ry}rz(hh?h@h\hB}r|(hF]hG]hE]hD]hH]uhJM=hKhh7]r}h_X Batch Readingr~…�r}r€(hh?h@hfhB}rƒ(hF]hG]hE]hD]hH]uhJM?hKhh7]r„(h_X‰Similar to batch writing, batch reading can also help reduce the number of API requests necessary to access a large number of items. The r……�r†}r‡(hh?h@hfhB}r•(hF]hG]hE]hD]hH]uhJMDhKhh7]r–h_XîThis is done lazily, so if you never iterate over the results, no requests are executed. Additionally, if you only iterate over part of the set, the minumum number of calls are made to fetch those results (typically max 100 per response).r—…�r˜}r™(hh?h@hfhB}r�(hF]hG]hE]hD]hH]uhJMIhKhh7]ržh_XExample:rŸ…�r }r¡(h>> from boto.dynamodb2.table import Table >>> users = Table('users') # No request yet. >>> many_users = users.batch_get(keys=[ {'username': 'alice'}, {'username': 'bob'}, {'username': 'fred'}, {'username': 'jane'}, {'username': 'johndoe'}, ]) # Now the request is performed, requesting all five in one request. >>> for user in many_users: ... print user['first_name'] 'Alice' 'Bobby' 'Fred' 'Jane' 'John'h=jsh>h?h@j£hB}r¤(j¥j¦hD]hE]hF]hG]hH]uhJMKhKhh7]r¥h_X¯>>> from boto.dynamodb2.table import Table >>> users = Table('users') # No request yet. >>> many_users = users.batch_get(keys=[ {'username': 'alice'}, {'username': 'bob'}, {'username': 'fred'}, {'username': 'jane'}, {'username': 'johndoe'}, ]) # Now the request is performed, requesting all five in one request. >>> for user in many_users: ... print user['first_name'] 'Alice' 'Bobby' 'Fred' 'Jane' 'John'r¦…�r§}r¨(hh?h@hQhB}r«(hF]hG]hE]hD]r¬h'ahH]r­h auhJMbhKhh7]r®(hX)�r¯}r°(hh?h@h\hB}r²(hF]hG]hE]hD]hH]uhJMbhKhh7]r³h_XDeleting a Tabler´…�rµ}r¶(hh?h@hfhB}r¹(hF]hG]hE]hD]hH]uhJMdhKhh7]rºh_XSDeleting a table is a simple exercise. When you no longer need a table, simply run:r»…�r¼}r½(h>> users.delete()h=j©h>h?h@j£hB}rÀ(j¥j¦hD]hE]hF]hG]hH]uhJMghKhh7]rÁh_X>>> users.delete()rÂ…�rÃ}rÄ(hh?h@hQhB}rÇ(hF]hG]hE]hD]rÈh4ahH]rÉhauhJMkhKhh7]rÊ(hX)�rË}rÌ(hh?h@h\hB}rÎ(hF]hG]hE]hD]hH]uhJMkhKhh7]rÏh_XDynamoDB LocalrÐ…�rÑ}rÒ(hh?h@hfhB}rÕ(hF]hG]hE]hD]hH]uhJMmhKhh7]rÖ(hl)�r×}rØ(hh?h@j£hB}rä(j¥j¦hD]hE]hF]hG]hH]uhJMphKhh7]råh_X#!/usr/bin/env python from boto.dynamodb2.layer1 import DynamoDBConnection # Connect to DynamoDB Local conn = DynamoDBConnection( host='localhost', port=8000, aws_secret_access_key='anything', is_secure=False) # List all local tables tables = conn.list_tables()ræ…�rç}rè(hh?h@hAhB}rë(hrjÚhD]rìh1ahE]hF]hG]hH]ríhauhJMhKhh7]ubeubhL)�rî}rï(hh?h@hQhB}rð(hF]hG]hE]hD]rñh,ahH]ròhauhJMƒhKhh7]ró(hX)�rô}rõ(hh?h@h\hB}r÷(hF]hG]hE]hD]hH]uhJMƒhKhh7]røh_X Next Stepsrù…�rú}rû(h`.h=jîh>h?h@hfhB}rþ(hF]hG]hE]hD]hH]uhJM…hKhh7]rÿ(h_XQYou can find additional information about other calls & parameter options in the r…�r}r(h`rh=jüh>h?h@hžhB}r(UreftypeXdocrh¡ˆh¢X ref/dynamodb2U refdomainUhD]hE]U refexplicitˆhF]hG]hH]h£h¤uhJM…h7]rh¦)�r }r (h}r?(Ufootnote_backlinksr@KUrecord_dependenciesrANU rfc_base_urlrBUhttp://tools.ietf.org/html/rCU tracebackrDˆUpep_referencesrENUstrip_commentsrFNU toc_backlinksrGUentryrHU language_coderIUenrJU datestamprKNU report_levelrLKU _destinationrMNU halt_levelrNKU strip_classesrONh\NUerror_encoding_error_handlerrPUbackslashreplacerQUdebugrRNUembed_stylesheetrS‰Uoutput_encoding_error_handlerrTUstrictrUU sectnum_xformrVKUdump_transformsrWNU docinfo_xformrXKUwarning_streamrYNUpep_file_url_templaterZUpep-%04dr[Uexit_status_levelr\KUconfigr]NUstrict_visitorr^NUcloak_email_addressesr_ˆUtrim_footnote_reference_spacer`‰UenvraNUdump_pseudo_xmlrbNUexpose_internalsrcNUsectsubtitle_xformrd‰U source_linkreNUrfc_referencesrfNUoutput_encodingrgUutf-8rhU source_urlriNUinput_encodingrjU utf-8-sigrkU_disable_configrlNU id_prefixrmUU tab_widthrnKUerror_encodingroUUTF-8rpU_sourcerqh?Ugettext_compactrrˆU generatorrsNUdump_internalsrtNU smart_quotesru‰U pep_base_urlrvUhttp://www.python.org/dev/peps/rwUsyntax_highlightrxUlongryUinput_encoding_error_handlerrzjUUauto_id_prefixr{Uidr|Udoctitle_xformr}‰Ustrip_elements_with_classesr~NU _config_filesr]Ufile_insertion_enabledr€ˆU raw_enabledr�KU dump_settingsr‚NubUsymbol_footnote_startrƒKUidsr„}r…(h+h{h5hÌh-j‡h3hëh(jÌh'j©h)jyh*j#h1jéh#hMh/j h4jÅh.jh&jh%jñh$jºh,jîh0jsh6jh2hMuUsubstitution_namesr†}r‡h@hKhB}rˆ(hF]hD]hE]Usourceh?hG]hH]uU footnotesr‰]rŠUrefidsr‹}rŒh2]r�h:asub.