DynamoDb: запрос сканирования не возвращает все данные

У меня есть таблица DynamoDb с тысячами данных. Я просматриваю таблицу с помощью функции сканирования и применил «Между» FilterExpression. Однако ответ на запрос дает только 3 записи, тогда как он должен возвращать около 100 записей.

Я создал функцию Lambda, используя Node js.


person Sumera    schedule 14.04.2017    source источник
comment
Наиболее вероятная причина в том, что выражение фильтра отфильтровывает некоторые значения. В этом случае DynamoDB все равно должен сканировать всю таблицу и пролистывать результаты. Каждый ответ будет включать только те элементы, которые соответствуют условию фильтра, и LastEvaluateKey, который вы должны включить в следующий запрос, чтобы продолжить сканирование. Сначала это немного неинтуитивно, но имеет смысл, если вы немного задумаетесь.   -  person Mike Dinescu    schedule 14.04.2017
comment
Чтобы получить / отсканировать все элементы из AWS Dynamodb с помощью Node.js, вы можете обратиться к: stackoverflow.com/questions/44589967/   -  person Yuci    schedule 31.07.2020


Ответы (3)


Другая распространенная проблема может заключаться в том, выполняется ли сканирование до тех пор, пока LastEvaluatedKey не станет пустым.

Если вы уже делаете это и по-прежнему не получаете все элементы, покажите свой код, чтобы подробно изучить его.

Если общее количество отсканированных элементов превышает максимальный размер набора данных в 1 МБ, сканирование останавливается и результаты возвращаются пользователю в виде значения LastEvaluatedKey для продолжения сканирования в последующей операции. Результаты также включают количество элементов, превышающих лимит. В результате сканирования данные таблицы могут не соответствовать критериям фильтра.

Если LastEvaluatedKey пуст, значит, «последняя страница» результатов была обработана и больше нет данных для извлечения.

Если LastEvaluatedKey не пуст, это не обязательно означает, что в наборе результатов больше данных. Единственный способ узнать, когда вы достигли конца набора результатов, - это когда LastEvaluatedKey пуст.

person notionquest    schedule 16.04.2017

Вот пример кода для получения всех результатов:

 Map<String, AttributeValue> lastKeyEvaluated = null;
    do {
        ScanRequest sr = new ScanRequest()
                .withTableName("tableName")
                .withProjectionExpression("id")
                .withExclusiveStartKey(lastKeyEvaluated);
        ScanResult result = client.scan(sr);
        for (Map<String, AttributeValue> item : result.getItems()) {
            System.out.println(item.get("id").getS());
        }
        lastKeyEvaluated = result.getLastEvaluatedKey();
    } while (lastKeyEvaluated != null);
person Michael    schedule 28.02.2018
comment
Пожалуйста, добавьте описание к своему ответу. - person not2qubit; 01.03.2018
comment
Этот ответ очень помог, спасибо. Однако обратите внимание, что с AWS SDK 2.0 result.getLastEvaluatedKey() возвращает пустую, а не нулевую карту. Поэтому мне просто нужно было изменить условие while, чтобы проверить != null && !empty. - person dewald; 27.02.2020

Используя Node.js, я использую Query для извлечения элементов из базы данных. Одна операция запроса может получить максимум 1 МБ данных. Вот почему я создал рекурсивную функцию для извлечения и объединения данных из базы данных до тех пор, пока мы не получим LastEvaluatedKey из ответа. Когда мы получаем LastEvaluatedKey как null, это означает, что данных больше нет. Моя функция использует индекс для получения данных из базы данных. Использование функций запроса будет работать быстрее и эффективнее, чем сканирование.

Собственно, у функции getItemByGSI очень много параметров для фильтрации и настройки запроса, которые могут быть полезны. И, конечно, вы можете удалить параметры, которые не нужны для вашего случая.

Таким образом, функцию getAllItemsByGSI можно использовать для получения всех данных из DynamoDB, а getItemByGSI можно использовать для использования одного запроса.

'use strict';
    
    const omitBy = require('lodash/omitBy');
    const isNil = require('lodash/isNil');
    const AWS = require('aws-sdk');
    
    const call = (action, params) => {
        return new Promise((resolve, reject) => {
            try {
                const dynamoDb = new AWS.DynamoDB.DocumentClient();
                resolve(dynamoDb[action](params).promise());
            } catch (error) {
                reject(error);
            }
        });
    };
    
    const getItemByGSI = ({
        TableName,
        IndexName,
        attribute,
        value,
        sortKey,
        sortValue,
        filter,
        filterValue,
        operator,
        filter1,
        filterValue1,
        LastEvaluatedKey,
        ScanIndexForward,
        Limit,
    }) => {
        return new Promise(async (resolve, reject) => {
            try {
                const params = {
                    TableName,
                    IndexName,
                    KeyConditionExpression: '#attrKey = :attrValue',
                    ExpressionAttributeValues: { ':attrValue': value },
                    ExpressionAttributeNames: { '#attrKey': attribute },
                    ExclusiveStartKey: LastEvaluatedKey,
                    Limit,
                    FilterExpression: null,
                };
                sortKey && sortValue
                    ? (params.KeyConditionExpression +=
                            ' and #sortKey = :sortValue' &&
                            (params.ExpressionAttributeNames['#sortKey'] = sortKey) &&
                            (params.ExpressionAttributeValues[':sortKey'] = sortValue))
                    : '';
                filter && filterValue
                    ? (params.FilterExpression = `#${filter} = :${filter}`) &&
                      (params.ExpressionAttributeNames[`#${filter}`] = filter) &&
                      (params.ExpressionAttributeValues[`:${filter}`] = filterValue)
                    : '';
                filter && filterValue && operator && filter1 && filterValue1
                    ? (params.FilterExpression += ` ${operator} #${filter1} = :${filter1}`) &&
                      (params.ExpressionAttributeNames[`#${filter1}`] = filter1) &&
                      (params.ExpressionAttributeValues[`:${filter1}`] = filterValue1)
                    : '';
                params = omitBy(params, isNil);
                if (ScanIndexForward === false)
                    params.ScanIndexForward = ScanIndexForward;
                const result = await call('query', params);
                resolve(result);
            } catch (error) {
                reject(error);
            }
        });
    };
    
    const getAllItemsByGSI = (data) => {
        return new Promise(async (resolve, reject) => {
            try {
                const finalData = [];
                const gettingData = await getItemByGSI(data);
                finalData = finalData.concat(gettingData.Items);
                if (gettingData.LastEvaluatedKey) {
                    const final2 = await getAllItemsByGSI({
                        ...data,
                        LastEvaluatedKey: gettingData.LastEvaluatedKey,
                    });
                    finalData = finalData.concat(final2);
                }
                resolve(finalData);
            } catch (err) {
                reject(err);
            }
        });
    };
    
    module.exports = {
        getItemByGSI,
        getAllItemsByGSI,
    };

person CyberEternal    schedule 24.06.2021