Вопрос или проблема
Фильтрация значений вложенного поля в DynamoDB с использованием Golang
Название таблицы: MyTable
Имя атрибута: data
Ключевое слово для фильтрации: rally
Как отфильтровать элементы, где массив attributes.label
содержит rally
?
{
"type": {
"S": "play"
},
"attributes": {
"M": {
"term": {
"S": "end_term"
},
"label": {
"L": [
{
"S": "all_players"
},
{
"S": "rally"
},
{
"S": "race"
}
]
},
"currency": {
"S": "USD"
}
}
},
"id": {
"S": "a752d2"
}
}
Я использовал приведённый ниже пример, но он всегда возвращает 0
элементов.
input := &dynamodb.ScanInput{
TableName: aws.String("MyTable"),
FilterExpression: aws.String("contains(#path, :keyword)"),
ExpressionAttributeNames: map[string]string{
"#path": "attributes.label",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":keyword": &types.AttributeValueMemberS{Value: "rally"},
},
}
result, err := c.client.Scan(context.TODO(), input)
if err != nil {
log.Fatalf("не удалось просканировать элементы: %v", err)
}
fmt.Println(">>>>> Результат", len(result.Items))
for i, item := range result.Items {
var data map[string]interface{}
err := json.Unmarshal([]byte(item["data"].(*types.AttributeValueMemberS).Value), &data)
if err != nil {
log.Printf("не удалось преобразовать элемент: %v", item)
continue
}
fmt.Printf(">>>>> Элемент (%d): %+v", i, data)
}
Ответ или решение
Для фильтрации элементов в таблице DynamoDB на основе значений вложенных полей, таких как массив attributes.label
, необходимо правильно сформулировать FilterExpression
и использовать правильные ключи в ExpressionAttributeNames
. В вашем случае пытаемся фильтровать элементы по значению "rally" в массиве. Однако, есть небольшая ошибка в вашем примере.
Вот исправленный код на языке Go, который фильтрует элементы по условию, что массив attributes.label
содержит значение "rally":
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Item struct {
ID string `json:"id"`
Type string `json:"type"`
Attributes struct {
Term string `json:"term"`
Label []string `json:"label"`
Currency string `json:"currency"`
} `json:"attributes"`
}
func main() {
sess := session.Must(session.NewSession())
svc := dynamodb.New(sess)
input := &dynamodb.ScanInput{
TableName: aws.String("MyTable"),
FilterExpression: aws.String("contains(#path, :keyword)"),
ExpressionAttributeNames: map[string]*string{
"#path": aws.String("attributes.label"),
},
ExpressionAttributeValues: map[string]*dynamodb.AttributeValue{
":keyword": {
S: aws.String("rally"),
},
},
}
result, err := svc.Scan(input)
if err != nil {
log.Fatalf("failed to scan items: %v", err)
}
fmt.Println(">>>> Result", len(result.Items))
for i, item := range result.Items {
var data Item
err := dynamodbattribute.UnmarshalMap(item, &data)
if err != nil {
log.Printf("failed to unmarshal item: %v", item)
continue
}
fmt.Printf(">>>> Item (%d): %+v\n", i, data)
}
}
Объяснение исправлений:
-
Использование
dynamodbattribute.UnmarshalMap
: Ваша попытка развернуть элементы из формата DynamoDB в структурированный формат не была корректной. Использованиеdynamodbattribute.UnmarshalMap
позволяет более правильно обработать данные. -
ExpressionAttributeNames
: Убедитесь, что#path
ссылается наattributes.label
, так как вы пытаетесь использовать это выражение в фильтре. - Типы и структура: Определите структуру Item, чтобы корректно отображать связанные данные. Это поможет вам удобно управлять и обрабатывать полученные данные.
Обратите внимание, что Scan
может возвращать большую нагрузку данных, что может не быть оптимальным решением, если ваши таблицы становятся большими. Рассмотрите использование метода Query
, если имена ваших ключей известны и позволяют это.
Теперь с помощью приведенного исправленного кода вы сможете отфильтровать элементы по наличию значения "rally" в массиве attributes.label
.