AWS DynamoDB Scan and FilterExpression using array of hash values
I had this issue and figured it out by using contains parameter
// Object stored in the DB looks like this:
// [
// 'name' => 'myName',
// 'age' => '24',
// 'gender' => 'Male',
// 'visited' => [
// 'countries': ['Canada', 'USA', 'Japan', 'Australia'],
// 'last_trip': '2015/12/13',
// 'reviews_written': 20
// ]
//
// ];
$countries = ['Canada', 'USA', 'Japan', 'Australia'];
$paramToMatch = '24';
$client->query([
'TableName' => 'MyDyanmoDB',
'KeyConditions' => [
'age' => [
'AttributeValueList' => [
$marshaler->marshalValue($paramToMatch)
],
'ComparisonOperator' => 'EQ'
]
],
'ExpressionAttributeNames' => [
'#visited' => 'visited',
'#countries' => 'countries'
],
'ExpressionAttributeValues' => [
':countries' => $marshaler->marshalValue($countries)
],
'FilterExpression' => 'contains(:countries, #visited.#countries)',
]);
Here's how I was able to use "scan" to get the items with a particular ID ("ContentID") in below example:
var params = {
TableName: environment.ddbContentTableName,
ProjectionExpression: "Title, ContentId, Link",
FilterExpression: "ContentId in (:contentId1, :contentId2, :contentId3, :contentId4)",
ExpressionAttributeValues: {":contentId1":102,":contentId2":104,":contentId3":103,":contentId4":101}
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.scan(params, onQuery);
I can then programmatically construct the FilterExpression and ExpressionAttributeValues based on known values e.g.
// Create the FilterExpression and ExpressionAttributeValues
var filterExpression = "ContentId in (";
var expressionAttributeValues = {};
for (var i = 0; i < currentFavorites.length; i++) {
var contentIdName = ":contentId"+(i+1);
if (i==0) {
filterExpression = filterExpression + contentIdName;
} else {
filterExpression = filterExpression + ", " + contentIdName;
}
expressionAttributeValues[contentIdName] = currentFavorites[i];
}
filterExpression = filterExpression + ")";
var params = {
TableName: environment.ddbContentTableName,
ProjectionExpression: "Title, ContentId, Link",
FilterExpression: filterExpression,
ExpressionAttributeValues: expressionAttributeValues
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.scan(params, onQuery);
You should make use of the IN
operator. It is also easier to use Placeholders for attribute names and attribute values. I would, however, advise against using a Scan
in this case. It sounds like you already have the hash key attribute values that you want to find, so it would make more sense to use BatchGetItem
.
Anyways, here is how you would do it in Java:
ScanSpec scanSpec = new ScanSpec()
.withFilterExpression("#idname in (:val1, :val2, :val3)")
.withNameMap(ImmutableMap.of("#idname", "ID"))
.withValueMap(ImmutableMap.of(":val1", "123", ":val2", "456", ":val23", "789"));
ItemCollection<ScanOutcome> = table.scan(scanSpec);
I would imagine using the Javascript SDK it would be something like this:
var scanParams = {
"TableName":"myAwsTable",
"AttributesToGet": ['ID','COMMENTS','DATE'],
"FilterExpression": '#idname in (:val1, :val2, :val3)',
"ExpressionAttributeNames": {
'#idname': 'ID'
},
"ExpressionAttributeValues": {
':val1': '123',
':val2': '456',
':val3': '789'
}
}