[amazon-dynamodb] DynamoDB에서 쿼리 또는 스캔을 사용하여 결과를 주문할 수 있습니까?

DynamoDB에서 Query 또는 Scan API를 사용하여 결과를 주문할 수 있습니까?

DynamoDB에 SQL 쿼리의 [ORDER BY ‘field’]와 같은 것이 있는지 알고 싶습니다.

감사.



답변

그러나 명시 적으로는 아니지만 많은 실제 사용 사례에서 순서가 분명히 필요하며 그에 따라 해시 및 범위 유형 기본 키 를 사용하여 모델링 할 수 있습니다 .

이 경우 기본 키는 두 가지 속성으로 구성됩니다. 첫 번째 속성은 해시 속성이고 두 번째 속성은 범위 속성입니다. Amazon DynamoDB는 해시 기본 키 속성에 정렬되지 않은 해시 인덱스를 만들고 범위 기본 키 속성에 정렬 된 범위 인덱스를 만듭니다. [내 강조]

그런 다음을 통해 선택적으로 요청 항목이 범위 인덱스를 사용할 수 있습니다 RangeKeyCondition의 의 매개 변수 쿼리 API 및 지정 앞이나 인덱스의 뒤로 통과 비아 (즉, 정렬 방향) ScanIndexForward 매개 변수입니다.

업데이트 : 동일한 방식으로 local secondary index 가있는 속성별로 주문할 수 있습니다 .


답변

정렬 키를 사용하고 쿼리 에 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));
    }
});


답변

ScanIndexForward (오름차순은 true, 내림차순은 false)를 사용하고 쿼리 표현식의 setLimit 값을 사용하여 결과를 제한 할 수도 있습니다.

단일 레코드를 찾기 위해 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());
    }
}


답변

문제를 해결해야하는 또 다른 옵션은

  1. LSI의 해시 키가 될 “일반”해시 키를 사용하여 local secondary index를 정의합니다.
  2. LSI의 “정렬 키”로 정렬하려는 필드를 정의하십시오.
  3. LSI를 쿼리하고 원하는대로 순서를 설정합니다 (위 참조).

이렇게하면 필요에 따라 테이블 값을 정렬 할 수 있습니다. 전체 쿼리를 가져온 다음 나중에 필터링 할 필요없이 테이블에서 가장 높은 순위의 항목을 찾는 매우 효율적인 방법입니다.


답변

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는 사실, DynamoDB의 그들이 (정렬 키 값에 의해) 저장되는 순서대로 결과를 반환합니다. 이것이 기본 동작입니다. ScanIndexForward가 false이면 DynamoDB는 정렬 키 값에 따라 역순으로 결과를 읽은 다음 결과를 클라이언트에 반환합니다.


답변

테이블이 이미 존재하는 경우 테이블에 대해 원하는 속성에 GSI (Global Secondary Index)를 추가하고 Scan이 아닌 Query를 사용합니다. 테이블을 생성하려는 경우 원하는 속성에 LSI (Local Secondary Index)를 추가 할 수 있습니다.


답변

그런 사소한 작업이 DynamoDB에서 문제가 될 수 있다고는 생각하지 못했습니다. Dynamo에는 몇 가지 기본 파티션이 필요합니다. 추가 열 상태를 추가하여 데이터를 주문했습니다. 다음 두 필드를 사용하여 GSI 인덱스를 생성했습니다. createdAt 필드에서 status = “active”인 데이터를 주문합니다.

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"
  },
});