Для веб-приложения я хочу реализовать разбитый на страницы таблицы. «Макет» DynamoDB заключается в том, что для пользователя есть несколько элементов, поэтому я выбрал partition key=user
и sort key=created
(временная метка). Пользовательский интерфейс должен представить элементы на страницах с 50 элементами из всего нескольких элементов.PaginatedList DynamoDB через REST
Элементы передаются в пользовательский интерфейс через вызовы REST-Api. Я хочу только query
или scan
страницы, а не всю таблицу. Разбиение страницы возможно вперед и назад.
До сих пор я придумал с нижеследующим, используя DynamoDBMapper
:
/**
* Returns the next page of items DEPENDENT OF THE USER. Note: This method internally uses
* DynamoDB QUERY. Thus it requires "user" as a parameter. The "created" parameter is optional.
* If provided, both parameters form the startKey for the pagination.
*
* @param user - mandatory: The user for which to get the next page
* @param created - optional: for providing a starting point
* @param limit - the returned page will contain (up to) this number of items
* @return
*/
public List<SampleItem> getNextPageForUser(final String user, final Long created, final int limit) {
// To iterate DEPENDENT on the user we use QUERY. The DynamoDB QUERY operation
// always require the partition key (=user).
final SampleItem hashKeyObject = new SampleItem();
hashKeyObject.setUser(user);
// The created is optional. If provided, it references the starting point
if (created == null) {
final DynamoDBQueryExpression<SampleItem> pageExpression = new DynamoDBQueryExpression<SampleItem>()//
.withHashKeyValues(hashKeyObject)//
.withScanIndexForward(true) //
.withLimit(limit);
return mapper.queryPage(SampleItem.class, pageExpression).getResults();
} else {
final Map<String, AttributeValue> startKey = new HashMap<String, AttributeValue>();
startKey.put(SampleItem.USER, new AttributeValue().withS(user));
startKey.put(SampleItem.CREATED, new AttributeValue().withN(created.toString()));
final DynamoDBQueryExpression<SampleItem> pageExpression = new DynamoDBQueryExpression<SampleItem>()//
.withHashKeyValues(hashKeyObject)//
.withExclusiveStartKey(startKey)//
.withScanIndexForward(true) //
.withLimit(limit);
return mapper.queryPage(SampleItem.class, pageExpression).getResults();
}
}
Код для предыдущего похож, только то, что он использует withScanIndexForward(false)
.
В моем контроллере REST-Api Я предлагаю один метод:
@RequestMapping(value = "/page/{user}/{created}", method = RequestMethod.GET)
public List<SampleDTO> listQueriesForUserWithPagination(//
@RequestParam(required = true) final String user,//
@RequestParam(required = true) final Long created,//
@RequestParam(required = false) final Integer n,//
@RequestParam(required = false) final Boolean isBackward//
) {
final int nrOfItems = n == null ? 100 : n;
if (isBackward != null && isBackward.booleanValue()) {
return item2dto(myRepo.getPrevQueriesForUser(user, created, nrOfItems));
} else {
return item2dto(myRepo.getNextQueriesForUser(user, created, nrOfItems));
}
}
Интересно, если я заново изобретать колесо с таким подходом.
Можно ли передать DynamicDB PaginatedQueryList
или PaginatedScanList
в UI через REST, так что, если javascript разбивает страницы на элементы, то тогда они загружаются лениво. От работы с другими БД я никогда не передавал объекты записи БД, поэтому мой код-фрагмент повторно упаковывает данные (item2dto
).
Кроме того, разбиение на страницы с DynamoDB выглядит несколько странно: до сих пор я не видел возможности предоставить пользовательскому интерфейсу общее количество элементов. Таким образом, пользовательский интерфейс имеет только кнопки для «следующей страницы» и «предыдущей страницы», не зная, сколько страниц будет следовать. Поэтому прямое переключение на страницу 5 невозможно.