0
votes

I would like to ask about filterExpression for AWSDynamoDBScanExpression. Problem:

I want to scan db for all object in one table where one parameter (lets call it uniqueId) is one of the value stored in array (array of required uniqueIds).

For one object - it's easy to do with

AWSDynamoDBScanExpression *scanExpression = [[AWSDynamoDBScanExpression alloc] init];
scanExpression.expressionAttributeNames = @{
                                            @"#P": [NSString stringWithFormat:@"%@", property]
                                            };
scanExpression.filterExpression =@"#P = :val";
scanExpression.expressionAttributeValues = @{
                                             @":val" : @"some uniqueID"
                                             };

so in same logic i want to scan db for multi objects

 AWSDynamoDBScanExpression *scanExpression = [[AWSDynamoDBScanExpression alloc] init];
scanExpression.expressionAttributeNames = @{
                                            @"#P": [NSString stringWithFormat:@"%@", property]
                                            };
scanExpression.filterExpression = <WHAT SHOULD BE HERE, WHAT EXPRESSION>;
scanExpression.expressionAttributeValues = @{
                                             @":val" : [@"some unique id 1", 
                                             @"some unique id 2",
                                             @"some unique id 3"]
                                             };

Is any way to change scanExpression.filterExpression to achive this?

EDIT 1

No, I'm not sure that scan is the best solution. Actually query is best variant think.

The structure of table

enter image description here

#P = :val1 OR #P = :val2 make sense

EDIT2

This is some update:

AWSDynamoDBQueryExpression *query = [[AWSDynamoDBQueryExpression alloc] init];
NSMutableDictionary *dictionaryAttributes = [[NSMutableDictionary alloc] init];
NSString *expression = @"";
for (int i = 0; i < filteredHashValues.count; i++) {
    NSString *variableName = [NSString stringWithFormat:@":val%i", i];
    [dictionaryAttributes setValue:filteredHashValues[i] forKey:variableName];
    expression = [expression stringByAppendingString:expression.length ? [NSString stringWithFormat:@"OR #P = %@ " , variableName] : [NSString stringWithFormat:@"#P = %@ " , variableName]];
}

query.indexName = @"uniqueId-index";
query.expressionAttributeNames = @{
                                   @"#P": [NSString stringWithFormat:@"%@", @"uniqueId"]
                                   };
query.filterExpression = expression;
query.expressionAttributeValues = dictionaryAttributes;

AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
[[dynamoDBObjectMapper query:className expression:query] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {

    if (task.result) {
        AWSDynamoDBPaginatedOutput *output = task.result;
    }
    return nil;
}];

But result

Printing description of expression: #P = :val0 OR #P = :val1 OR #P = :val2 OR #P = :val3

Printing description of dictionaryAttributes: { ":val0" = "8A93A3EA-9FB9-4396-BBF6-D0BD3CBE6BE5"; ":val1" = "08533EBA-D3E5-406C-8CDE-03EECCCA801B"; ":val2" = "954AE402-336E-423D-BF03-7E8AED1446FE"; ":val3" = "F683BDF8-0507-4218-9927-9F14D470E593"; }

Printing description of task->_error: Error `Domain=com.amazonaws.AWSDynamoDBErrorDomain Code=0 "(null)" UserInfo={__type=com.amazon.coral.validate#ValidationException, message=ExpressionAttributeValues contains invalid value: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes for key :awsddbomhashvalueplaceholder}

looks like ExpressionAttributeValues is empty - am i doing all correct?

1

1 Answers

1
votes

are you sure that you want to use a scan expression? this really consumes a lot of read capacity and can ruine your dynamodb performances: a scan reads you entire table and only THEN applies the filter and returns the values.

if you provide us with your actual dynamodb table structure we could maybe discuss another solution. For example a solution could be to create a global secondary index (if eventual consistent read is ok for you) or a local secondary index (along with its limitations), with a range key on your value to filter. This would allow you to use queries, which is much nicer and advised as of best practices.

That been said, you can just add conditions to your filter using AND and OR operators, resulting in sth similar to "#P = :val1 OR #P = :val2"

hope that helps