Фильтрация значений вложенного поля в DynamoDB с использованием Golang

Вопрос или проблема

Фильтрация значений вложенного поля в 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)
    }
}

Объяснение исправлений:

  1. Использование dynamodbattribute.UnmarshalMap: Ваша попытка развернуть элементы из формата DynamoDB в структурированный формат не была корректной. Использование dynamodbattribute.UnmarshalMap позволяет более правильно обработать данные.

  2. ExpressionAttributeNames: Убедитесь, что #path ссылается на attributes.label, так как вы пытаетесь использовать это выражение в фильтре.

  3. Типы и структура: Определите структуру Item, чтобы корректно отображать связанные данные. Это поможет вам удобно управлять и обрабатывать полученные данные.

Обратите внимание, что Scan может возвращать большую нагрузку данных, что может не быть оптимальным решением, если ваши таблицы становятся большими. Рассмотрите использование метода Query, если имена ваших ключей известны и позволяют это.

Теперь с помощью приведенного исправленного кода вы сможете отфильтровать элементы по наличию значения "rally" в массиве attributes.label.

Оцените материал
Добавить комментарий

Капча загружается...