PynamoDB: Querying GlobalSecondaryIndex doesn't return all attributes
I have model with Primary and Range key and I also have GlobalSecondaryIndex defined with Primary and Range key as well. When I run query on the GlobalSercondarIndex I don’t get all the attributes of the model like I get when I run the query on the model it self. This happens even though the GlobalSecondaryIndex has projection set to AllProjection().
I’ve been struggling for some time and went a bunch of times over the documentation and it just doesn’t seem right.
Am I missing something here, or something is wrong with the query method when it is run on GlobalSecondaryIndex?
This is my definition of the GlobalSecondaryIndex and the model class
class MainTableMeta:
table_name = 'test-db-local'
region = os.environ['AWS_DEFAULT_REGION']
host = 'http://{}:{}'.format(os.environ['SLS_OFF_HOST'],
os.environ['DYNAMODB_PORT'])
class GlobalIndex1(GlobalSecondaryIndex):
"""
This class represents the global secondary index
"""
class Meta:
index_name = 'GS1-Index-local'
host = 'http://{}:{}'.format(os.environ['SLS_OFF_HOST'],
os.environ['DYNAMODB_PORT'])
region = os.environ['AWS_DEFAULT_REGION']
read_capacity_units = 2
write_capacity_units = 1
# All attributes are projected
projection = AllProjection()
gs1_pk = UnicodeAttribute(hash_key=True, attr_name="GS1PK")
gs1_sk = UnicodeAttribute(range_key=True, attr_name="GS1SK")
class Stimulus(Model):
"""
DynamoDb model for the Stimulus
"""
Meta = MainTableMeta
pk = UnicodeAttribute(hash_key=True, attr_name="PK")
sk = UnicodeAttribute(range_key=True, attr_name="SK")
gs1 = GlobalIndex1()
gs1_pk = UnicodeAttribute(attr_name="GS1PK")
gs1_sk = UnicodeAttribute(attr_name="GS1SK")
stimulus_id = UnicodeAttribute(attr_name="StimulusId")
index = NumberAttribute(attr_name="Index")
stimulus_type = UnicodeAttribute(attr_name="StimulusType")
areas_of_interest = JSONAttribute(attr_name="AreasOfInterest", null=True)
duration = NumberAttribute(attr_name="Duration")
open_end_question = BooleanAttribute(
attr_name="OpenEndQuestion", null=True)
questions = JSONAttribute(attr_name="Questions", null=True)
url = UnicodeAttribute(attr_name="Url")
date_created = UTCDateTimeAttribute(attr_name="DateCreated")
And this is how I call the query method on gs1
result = []
for stimulus in Stimulus.gs1.query(gs1_key, Stimulus.gs1_sk.startswith("STIMULUS#")):
result.append(stimulus.attribute_values)
When I execute this query, I don’t get back all the attributes in the Stimulus model, I get the keys attributes and tie stimulus_id and date_created attributes (the last two are not keys, just regular attributes). I tried and run the equivalent query on the same item over the primary key and it returned all the attributes. I am not sure why it is not returning all the items when the query is executed against the gs1 index?
Any help is really appreciated on this one. Thanks!
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 25 (8 by maintainers)
I just got a few new gray hairs trying to debug why the heck LSI queries were not projecting non-key attributes. In desperation, I started browsing all issues returned for the keyword “projection,” and I ended up here.
@DNakevski3Shape, nearly a year later, is there now a recommended approach for single-table designs with a single base class that defines keys, indexes, and common attributes and methods?
Given the following example code
How can I “instruct” the index to use the correct model and project all attributes when querying
DocumentInDB.LSI1_index?I think that this should be the go-to approach. When you have many models using the same table and indexes, the other one quickly becomes inconvenient and hard to maintain due to code duplication.
But the Index owner is set at the attribute assignment so I am not sure how to alter that from a child class.
Trying to do a naïve reproduction, it seems to work correctly:
However, the behavior observed by @DNakevski3Shape can be seen by changing:
This is indeed what happens – you’re reusing
GlobalIndex1for two models. However, when you use an index class in a model, the model takes “ownership” of that index class. In the short term, we should produce an error when an index class is already owned by a different model. In the long term, perhaps we can store the association with the instance of the index and not by modifying the index class. This would mean, however, that the following wouldn’t be possible anymore (I’m surprised it’s possible now… 🤷 ):