Search code examples
amazon-dynamodbdynamodb-queries

Searching a DynamoDB String Set Attribute by Array of Strings


I am struggling to find the correct syntax to search a String Set/List target attribute (tags) by an array of strings. The idea would be that if the SS attribute contains all of the passed strings, it passes the filter. The passed strings do not need to match all of the strings within the target attribute. The more strings you pass, the more accurate your results.

// Compile tags into a list
let tagSqlValues = {};
let tagSqlStatement = query.tags.map((tag: string, index: number) => {
  let tagParam = `:tag${index}`;
  tagSqlValues[tagParam] = tag;
  return `${tagParam} in tags`;
}).join(" and ");

// Console Logs
// tagSqlStatement = :tag0 in tags and :tag1 in tags (also tried tags contains :tag0 and tags contains :tag1)
// tagSqlValues = {":tag0":"Modern",":tag1":" Spring"}

let params = {
    TableName: "Art",
    FilterExpression: tagSqlStatement,
    ExpressionAttributeValues: tagSqlValues,
};
let results = await this.DDB_CLIENT.scan(params).promise();

// Console Logs
// "Invalid FilterExpression: Syntax error; token: \"tags\", near: \"in tags and\""
// "Invalid FilterExpression: Syntax error; token: \"contains\", near: \"tags contains :tag0\""

I've tried several variations with IN and CONTAINS without luck. Is this possible with DynamoDB?


Solution

  • It looks like my CONTAINS syntax was wrong. I did a little digging and found this answer by Zanon. With a minor modification to include the and join, it seems like the filter is working as expected!

    // Compile tags into a list
    let tagSqlValues = {};
    let tagSqlStatement = query.tags.map((tag: string, index: number) => {
      let tagParam = `:tag${index}`;
      tagSqlValues[tagParam] = tag;
      return `contains(tags, ${tagParam})`;
    }).join(" and ");