Czy można ZAMAWIAĆ wyniki za pomocą zapytania lub skanowania w DynamoDB?

86

Czy można ZAMAWIAĆ wyniki za pomocą interfejsu API zapytań lub skanowania w DynamoDB?

Muszę wiedzieć, czy DynamoDB ma coś takiego jak [ORDER BY „pole”] z zapytań SQL?

Dzięki.

Samuel Negru
źródło

Odpowiedzi:

44

Jednak nie jest to jednoznaczne, kolejność jest oczywiście potrzebna w wielu przypadkach użycia w świecie rzeczywistym i może być odpowiednio modelowana za pomocą klucza podstawowego typu Hash i Range Type :

W tym przypadku klucz podstawowy składa się z dwóch atrybutów. Pierwszy atrybut to atrybut hash, a drugi to atrybut range. Amazon DynamoDB buduje nieuporządkowany indeks skrótu na podstawie atrybutu klucza podstawowego skrótu i posortowany indeks zakresu na atrybucie klucza podstawowego zakresu . [podkreślenie moje]

Następnie można użyć tego indeksu zakresu, aby opcjonalnie zażądać elementów za pośrednictwem parametru RangeKeyCondition interfejsu API Query i określić przechodzenie indeksu w przód lub w tył (tj. Kierunek sortowania) za pomocą parametru ScanIndexForward .

Aktualizacja: w ten sam sposób można zamówić według atrybutu z lokalnym indeksem pomocniczym .

Steffen Opel
źródło
19
Wydaje się, że parametr ScanIndexForward ma zastosowanie tylko do zapytania , a nie do skanowania poprawnie? Jak można zwrócić uporządkowaną listę wszystkich elementów w tabeli, podzieloną na strony, używając zapytania? Wydaje się, że skanowanie jest sposobem na zwrócenie „*”, ale wydaje się, że nie ma parametru do porządkowania wyników.
case2000
Nie korzystałem z tej funkcji, tylko o niej czytałem, ale Query obsługuje określenie limitu , aby ograniczyć liczbę otrzymanych wyników, a jeśli po osiągnięciu limitu jest więcej pozycji pasujących do zapytania, otrzymasz LastEvaluatedKey które można wykorzystać do wykonania innego zapytania i kontynuowania pobierania wyników.
fernio
1
Ważny problem: zwrócone wyniki nie zostaną faktycznie posortowane. Sortowanie ma znaczenie tylko wtedy, gdy zastosujesz wartość „Limit” lub liczba elementów przekroczy limit wyszukiwania 1 MB. Np. Możesz mieć 5 rekordów z kluczem partycji „p1” i kluczami sortowania: [„b”, ​​„d”, „a”, „c”, „e”]. Jeśli wykonasz zapytanie tylko dla „p1”, otrzymasz [„b”, ​​„d”, „a”, „c”, „e”]. Ale jeśli określisz Limit
równy
29

Możesz użyć klawisza sortowania i zastosować parametr ScanIndexForward w zapytaniu, aby posortować je w porządku rosnącym lub malejącym. Tutaj ograniczam elementy zwracane do 1.

var params = {
    TableName: 'Events',
    KeyConditionExpression: 'Organizer = :organizer',
    Limit: 1,
    ScanIndexForward: false,    // true = ascending, false = descending
    ExpressionAttributeValues: {
        ':organizer': organizer
    }
};

docClient.query(params, function(err, data) {
    if (err) {
        console.log(JSON.stringify(err, null, 2));
    } else {
        console.log(JSON.stringify(data, null, 2));
    }
});
kometen
źródło
8
Problem polega na tym, że chcesz zwrócić wszystkie przedmioty. Zasadniczo oznacza to, że musisz utworzyć nową fikcyjną kolumnę, przypisać tę samą wartość do wszystkich wierszy, utworzyć GSI w tej kolumnie i wywołać zapytanie zamiast skanowania.
JHH
co jeśli chcę zwrócić na podstawie jakiegoś pola niebędącego kluczem? jak pole liczbowe created_on
Yusuf
Wtedy możesz chcieć pobrać wszystkie rekordy, a następnie przefiltrować je za pomocą javascript lub podobnego. DynamoDB to w zasadzie magazyn klucz-wartość o ograniczonej funkcjonalności. Ale jest bardzo szybki, gdy możesz użyć klucza (ów).
kometen
7

Użyj ScanIndexForward (true dla rosnąco i false dla malejąco), a także możesz ograniczyć wynik za pomocą wartości setLimit wyrażenia zapytania.

Poniżej znajduje się kod, w którym użyto QueryPage do znalezienia pojedynczego rekordu.

public void fetchLatestEvents() {
    EventLogEntitySave entity = new EventLogEntitySave();
    entity.setId("1C6RR7JM0JS100037_contentManagementActionComplete");

    DynamoDBQueryExpression<EventLogEntitySave> queryExpression = new DynamoDBQueryExpression<EventLogEntitySave>().withHashKeyValues(entity);
    queryExpression.setScanIndexForward(false);
    queryExpression.withLimit(1);
    queryExpression.setLimit(1);

    List<EventLogEntitySave> result = dynamoDBMapper.queryPage(EventLogEntitySave.class, queryExpression).getResults();
    System.out.println("size of records = "+result.size() );
}

@DynamoDBTable(tableName = "PROD_EA_Test")
public class EventLogEntitySave {

        @DynamoDBHashKey
        private String id;
        private String reconciliationProcessId;
        private String vin;
        private String source;
}

public class DynamoDBConfig {
    @Bean
    public AmazonDynamoDB amazonDynamoDB() {

            String accesskey = "";
            String secretkey = "";
            //
            // creating dynamo client
            BasicAWSCredentials credentials = new BasicAWSCredentials(accesskey, secretkey);
            AmazonDynamoDB dynamo = new AmazonDynamoDBClient(credentials);
            dynamo.setRegion(Region.getRegion(Regions.US_WEST_2));
            return dynamo;
        }

    @Bean
    public DynamoDBMapper dynamoDBMapper() {
        return new DynamoDBMapper(amazonDynamoDB());
    }
}
ABHAY JOHRI
źródło
Użyj ScanIndexForward (true dla rosnąco i false dla malejąco)
ABHAY JOHRI,
2

Inną opcją, która powinna rozwiązać problem, jest

  1. Zdefiniuj lokalny indeks pomocniczy z „normalnym” kluczem skrótu, który będzie również kluczem skrótu LSI
  2. Zdefiniuj pole, które chcesz sortować, jako „Klucz sortowania” LSI
  3. Zapytaj LSI i ustaw kolejność według potrzeb (patrz powyżej)

Umożliwi to sortowanie dowolnej wartości tabeli zgodnie z wymaganiami. Jest to bardzo skuteczny sposób znajdowania elementów o najwyższej pozycji w tabeli bez konieczności pobierania całego zapytania, a następnie filtrowania go.

Geole
źródło
Co powyżej? Jeśli normalny hash jest nieuporządkowany dla identyfikatora wygenerowanego przez sortowanie, to dołączenie go nie działa. Czy coś mi brakuje?
Samantha Atkins
1

Jeśli używasz boto2 i masz klucz sortowania w jednej z kolumn w tabeli, możesz posortować to, co pobierasz w kolejności lub w odwrotnej kolejności, mówiąc:

result = users.query_2(
    account_type__eq='standard_user',
    reverse=True)

Jeśli używasz boto3 i masz klucz sortowania w kolumnie, według której chcesz posortować wynik, możesz posortować dane, które pobierasz, mówiąc:

result = users.query(
    KeyConditionExpression=Key('account_type').eq('standard_user'),
    ScanIndexForward=True)

Pamiętaj, że w boto3, jeśli ScanIndexForward ma wartość true, DynamoDB zwraca wyniki w kolejności, w jakiej są przechowywane (według wartości klucza sortowania). To jest zachowanie domyślne. Jeśli ScanIndexForward ma wartość false, DynamoDB odczytuje wyniki w odwrotnej kolejności według wartości klucza sortowania, a następnie zwraca wyniki do klienta.

pilatipus
źródło
0

Jeśli tabela już istniała, dodaj GSI (Global Secondary Index) do atrybutu, który chcesz dla tabeli i użyj zapytania, a nie skanowania. Jeśli masz zamiar utworzyć tabelę, możesz dodać LSI (lokalny indeks pomocniczy) do żądanego atrybutu.

Sharhabeel Hamdan
źródło
0

Nigdy nie myślałem, że tak banalne zadanie może przerodzić się w problem w DynamoDB. Dynamo wymaga podstawowej partycji. Udało mi się uporządkować dane, dodając dodatkowy status kolumny, a następnie utworzyć indeks GSI przy użyciu obu pól. Zamawiam dane ze statusem = "aktywne" przez pole createdAt.

Utwórz GSI

{
        IndexName: "createdAt",
        KeySchema: [
            { AttributeName: "status", KeyType: "HASH" },
            { AttributeName: "createdAt", KeyType: "RANGE" }
        ],
        Projection: { ProjectionType: "ALL" },
        ProvisionedThroughput: {
          ReadCapacityUnits: N,
          WriteCapacityUnits: N
        }
      }

dane zapytania

const result = await this.dynamoClient.query({
  TableName: "my table",
  IndexName: "createdAt",
  KeyConditionExpression: "#status = :status and #createdAt > :createdAt",
  Limit: 5,
  ExpressionAttributeValues: {
    ":status": {
      "S": "active"
    },
    ":createdAt": {
      "S": "2020-12-10T15:00:00.000Z"
    }
  },
  ExpressionAttributeNames: {
    "#status": "status",
    "#createdAt": "createdAt"
  },
});
radzserg
źródło