Можно ли ЗАКАЗАТЬ результаты с запросом или сканированием в DynamoDB?


86

Можно ли ЗАКАЗАТЬ результаты с помощью API запросов или сканирования в DynamoDB?

Мне нужно знать, есть ли в DynamoDB что-то вроде [ORDER BY 'field'] из запросов SQL?

Благодарю.

Ответы:


44

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

В этом случае первичный ключ состоит из двух атрибутов. Первый атрибут - это хэш-атрибут, а второй - атрибут диапазона. Amazon DynamoDB строит неупорядоченный хэш-индекс по атрибуту первичного ключа хэша и отсортированный индекс диапазона по атрибуту первичного ключа диапазона . [курсив мой]

Затем вы можете использовать этот индекс диапазона для необязательного запроса элементов через параметр RangeKeyCondition API запросов и указать прямой или обратный обход индекса (т. Е. Направление сортировки) через параметр ScanIndexForward .

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


19
Параметр ScanIndexForward, кажется, применяется только к запросу , а не к сканированию правильно? Как с помощью Query вернуть упорядоченный список всех элементов таблицы с разбивкой на страницы? Кажется, что сканирование - это способ вернуть "*", но, похоже, у него нет параметра для упорядочивания результатов.
case2000,

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

1
Важный нюанс: возвращаемые результаты фактически не будут отсортированы. Сортировка вступает в игру только в том случае, если вы применяете значение «Limit» или количество элементов превышает лимит поиска в 1 МБ. Например, у вас может быть 5 записей с ключом раздела 'p1' и ключами сортировки: ['b', 'd', 'a', 'c', 'e']. Если вы выполните запрос только для 'p1', вы получите ['b', 'd', 'a', 'c', 'e']. Но если вы укажете предел 2, он вернет ['b', 'a']
jameslol

29

Вы можете использовать ключ сортировки и применить параметр ScanIndexForward в запросе для сортировки в порядке возрастания или убывания. Здесь я ограничиваю количество возвращаемых предметов 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));
    }
});

8
Проблема в том, что вы хотите вернуть все предметы. По сути, это означает, что вам нужно создать новый фиктивный столбец, присвоить в нем одно и то же значение всем строкам, создать GSI для этого столбца и вызвать запрос вместо сканирования.
JHH

что, если я хочу вернуться на основе какого-то неключевого поля? вроде created_on числовое поле
Юсуф

Затем вы можете получить все записи, а затем отфильтровать их с помощью javascript или аналогичного. DynamoDB - это, по сути, хранилище ключей и значений с ограниченной функциональностью. Но очень быстро, когда можно использовать ключ (и).
kometen

7

Используйте ScanIndexForward (true для возрастания и false для убывания), а также можете ограничить результат, используя значение setLimit в Query Expression.

Ниже приведен код, в котором QueryPage использовался для поиска отдельной записи.

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());
    }
}

Используйте ScanIndexForward (true для возрастания и false для убывания)
ABHAY JOHRI

2

Другой вариант, который должен решить проблему, - это

  1. Определите локальный вторичный индекс с «обычным» хеш-ключом, который также будет хеш-ключом LSI.
  2. Определите поле, которое вы хотите отсортировать, как «Ключ сортировки» LSI.
  3. Запросите LSI и установите желаемый порядок (см. Выше)

Это позволит отсортировать любое значение вашей таблицы по мере необходимости. Это очень эффективный способ найти элементы с наивысшим рейтингом в вашей таблице без необходимости получать весь запрос и затем фильтровать его.


Что выше? Если обычный хеш неупорядочен для идентификатора, сгенерированного сортировкой, то включение его, похоже, не работает. Я что-то упускаю?
Саманта Аткинс,

1

Если вы используете boto2 и у вас есть ключ сортировки в одном из столбцов вашей таблицы, вы можете отсортировать то, что вы получаете, по порядку или в обратном порядке, сказав:

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

Если вы используете boto3 и у вас есть ключ сортировки в столбце, по которому вы хотите отсортировать результат, вы можете отсортировать полученные данные, сказав:

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

Помните, что в boto3, если ScanIndexForward имеет значение true, DynamoDB возвращает результаты в том порядке, в котором они хранятся (по значению ключа сортировки). Это поведение по умолчанию. Если ScanIndexForward имеет значение false, DynamoDB считывает результаты в обратном порядке по значению ключа сортировки, а затем возвращает результаты клиенту.


0

Если таблица уже существует, добавьте GSI (глобальный вторичный индекс) к атрибуту, который вы хотите для таблицы, и используйте запрос, а не сканирование. Если вы собираетесь создать таблицу, вы можете добавить LSI (локальный вторичный индекс) к нужному атрибуту.


0

Никогда не думал, что такая банальная задача может превратиться в проблему в DynamoDB. Динамо требует некоторой базовой перегородки. Мне удалось упорядочить данные, добавив дополнительный статус столбца , а затем создать индекс GSI с использованием обоих полей. Я заказываю данные со статусом status = "active" по полю createdAt.

Создать GSI

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

данные запроса

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"
  },
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.