I am very new to DynamoDB and highly likely missing something. I read docs and other materials but couldn't work out missing link.
I am trying to query GSI by user email but no luck so far. Do I have to create a GSI separate from the table?
This is how I create table and secondary index:
{
"TableName": "BlogTable",
"KeySchema": [
{
"AttributeName": "PK",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
"AttributeDefinitions": [
{
"AttributeName": "PK",
"AttributeType": "S"
},
{
"AttributeName": "SK",
"AttributeType": "S"
}
],
"GlobalSecondaryIndexes": [
{
"IndexName": "BlogGlobalIndex1",
"KeySchema": [
{
"AttributeName": "PK",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "ALL"
},
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
This is how I put items in table:
// After this I can find item by user ID.
func (d DynamoDB) CreateUser(ctx context.Context, model store.User) error {
model.PrimaryKey = store.PrimaryKey{
PK: "user#" + model.ID,
SK: "user#" + model.ID,
}
item, err := attributevalue.MarshalMap(model)
if err != nil {
return fmt.Errorf("marshal map: %w", err)
}
_, err = d.Client.PutItem(ctx, &dynamodb.PutItemInput{
TableName: aws.String(d.Table),
Item: item,
})
if err != nil {
return fmt.Errorf("put item: %w", err)
}
return nil
}
This is how I am trying to query GSI but it yields 0 items when looking for items by email although there are matching items. Both options below won't work.
func (d DynamoDB) FindUserByEmail(ctx context.Context, email string) (store.User, error) {
cond1 := expression.Name("PK").Equal(expression.Value("user#" + email))
cond2 := expression.Name("SK").Equal(expression.Value("user#" + email))
expr, err := expression.NewBuilder().WithCondition(cond1.And(cond2)).Build()
if err != nil {
return store.User{}, fmt.Errorf("expression build: %w", err)
}
res, err := d.Client.Query(ctx, &dynamodb.QueryInput{
TableName: aws.String(d.Table),
IndexName: aws.String(d.GlobalIndex),
ExpressionAttributeNames: expr.Names(),
ExpressionAttributeValues: expr.Values(),
FilterExpression: expr.Filter(),
KeyConditionExpression: expr.Condition(),
ProjectionExpression: expr.Projection(),
// KeyConditionExpression: aws.String("PK = :PK, SK = :SK"),
// ExpressionAttributeValues: map[string]types.AttributeValue{
// "PK": &types.AttributeValueMemberS{Value: "user#" + email},
// "SK": &types.AttributeValueMemberS{Value: "user#" + email},
// },
// Limit: aws.Int32(1),
})
if err != nil {
return store.User{}, fmt.Errorf("get item: %w", err)
}
fmt.Println(res.Count) // 0
fmt.Println(len(res.Items)) // 0
var model store.User
// ...
return model, nil
}
Example data fixtures:
{
"Items": [
{
"SK": {
"S": "user#1722198720607873"
},
"Email": {
"S": "Shaylee54@gmail.com"
},
"PK": {
"S": "user#1722198720607873"
},
"ID": {
"S": "1722198720607873"
},
"Password": {
"S": "5O1AMjIG8hRFeS_"
},
"Name": {
"S": "Marty Ferry III"
}
},
{
"SK": {
"S": "user#1722178078008670"
},
"ID": {
"S": "1722178078008670"
},
"Email": {
"S": "Carissa11@yahoo.com"
},
"PK": {
"S": "user#1722178078008670"
},
"Name": {
"S": "Jana Rice"
},
"Password": {
"S": "OM9AfTTuwYPw_bD"
}
}
],
"Count": 2,
"ScannedCount": 2,
"ConsumedCapacity": null
}
Your GSI has the same KeySchema as the table - so it's just a "replica". You'll have to define the key(s) which you want to query (Documentation).
So, if your table has a field "email", use this in the KeySchema for the GSI. Then you can query it.
"GlobalSecondaryIndexes": [{
"IndexName": "BlogGlobalIndex1",
"KeySchema": [
{
"AttributeName": "email",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
...
}]
email
has also to be added to the AttributeDefinitions
.