How to query DynamoDB filtering by value in a list

Tags: , , , ,



There are three items in database:

[
  {
    "year": 2013,
    "info": {
      "genres": ["Action", "Biography"]
    }
  },
  {
    "year": 2013,
    "info": {
      "genres": ["Crime", "Drama", "Thriller"]
    }
  },
  {
    "year": 2013,
    "info": {
      "genres": ["Action", "Adventure", "Sci-Fi", "Thriller"]

    }
  }
]

With the year attribute being the table’s Primary Key I can go ahead and use the FilterExpression to match to the exact list value ["Action", "Biography"]:

var params = {
    TableName : TABLE_NAME,
    KeyConditionExpression: "#yr = :yyyy",
    FilterExpression: "info.genres = :genres",
    ExpressionAttributeNames:{
        "#yr": "year"
    },
    ExpressionAttributeValues: {
        ":yyyy": 2013,
        ":genres": ["Action", "Biography"]
    }     
};
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();


let promise = docClient.query(params).promise();
promise.then(res => {
console.log("res:", res);
})

Instead of matching an entire list ["Action", "Biography"] I would rather make a query to return only those table items that contain a string “Biography” in a list stored in the item’s info.genres field. I wonder if this possible using DynamoDB query API?

Edited later.

Working solution (Thanks to Balu) is to use QueryFilter contains comparison operator:

var params = {
    TableName: TABLE_NAME,
    Limit: 20,
    KeyConditionExpression: "id = :yyyy",
    FilterExpression: `contains(info.genres , :qqqq)`,
    ExpressionAttributeValues: {
      ":qqqq": { S: "Biography" },
      ":yyyy": { N: 2013 },
    },
  }

let promise = docClient.query(params).promise();
promise.then(res => {
console.log("res:", res);
})

Answer

We can use contains in Filter expressions instead of =.

So, "info.genres = :genres" can be changed to contains(info.genres , :gnOne)

AWS is still going to query on Partition Key extract max 1 MB of data in single query before applying the filter. so, we will be charged with same RCU with or without filter expression but amount of data returned to client will be limited, so, still useful.

const dynamodb = new AWS.DynamoDB();
dynamodb.query(
  {
    TableName: "my-test-table",
    Limit: 20,
    KeyConditionExpression: "id = :yyyy",
    FilterExpression: `contains(info.genres , :gnOne)`,
    ExpressionAttributeValues: {
      ":gnOne": { S: "Biography" },
      ":yyyy": { S: "2020" },
    },
  },
  function (err, data) {
    if (err) console.error(err);
    else console.log("dynamodb scan succeeded:", JSON.stringify(data, null, 2));
  }
);


Source: stackoverflow