Amazon DynamoDB Query for Items whose key contains a substring - amazon-web-services

I am using an Amazon DynamoDB database, and I have a list of items with various strings as the key. I want to query for items whose key contains a substring. For example, if some of the keys are:
"abcd_aaa"
"abcd_bbb"
"abcd_ccc"
I want to query where a key contains "abcd" and these 3 items will be returned. Is this possible?

You can only query the hashKey using the equality operator (EQ). That being said if those values ("abcd_aaa", "abcd_bbb", "abcd_ccc") belong to your hashKey then you have to provide them entirely. On the other hand, the Query operation does allow partial matching on the rangeKey with the option of a few additional comparison operators:
EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN
See the Query documentation for more details.
One possibility would be to use a hashKey and rangeKey where the first part of your code would be the hashKey and the last the rangeKey, example:
hashKey : abcd
rangeKey : aaa
By doing this when you query by hashKey (abcd), you would receive all three records sorted by the rangeKey

Scan will work
something like this
var params = {
TableName: "TABLE",
ScanFilter: {
"id": {
ComparisonOperator: "CONTAINS",
AttributeValueList: ["abcd"]
}
}
};
var template = null;
ddb.scan(params, function (err, data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
} else {
//console.log("Query succeeded.");
data.Items.forEach(function (item) {
console.log(item);
});
}
});

Related

How to query list of maps in DynamoDB table

I have a dynamo db table with InvId (Primary Partition Key) and PgNo (Primary Sort Key). There is an item in the table called Details which is a list of maps and every map has an attribute called ChargeId. How can I query the map having a particular ChargeId? Can someone help me with a solution how can I design the table so that I can pass the InvId and ChargeId to fetch the particular item from the Details list?
{
"Anytime": 0,
"Details": [
{
"AccNum": "ACCZ4402255319",
"Amt": 49.67,
"ChargeId": 1652849999
},
{
"AccNum": "ACCZ4402255319",
"Amt": 50,
"ChargeId": 1652849991
},
{
"AccNum": "ACCZ4402255319",
"Amt": 49.67,
"ChargeId": 1652849992
},
{
"AccNum": "ACCZ4402255319",
"Amt": 50,
"ChargeId": 1652849993
}
],
"ExpTime": 253402300800,
"InvId": "305_40225614",
"PgNo": 1,
"SubsId": "406890"
}
You need to use a filter expression. It won't be index optimized so be careful.
See DynamoDB: How to use a query filter to check for conditions in a MAP for a code sample.

DynamoDB Query with sort key and partition key

I am using JS SDK with DynamoDB to fetch data.
I am able to fetch data from my table using simple query with partition key and sort key.
My sort key sk has records -
Year#Batch#Rate
If I pass var sk = "2006#CSE#90"; it returns all of records matching this,
Requirement - How can I get all products with year 2006 , Batch CSE AND Rate =>90
readItem_pbro(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1";
var sk = "2006#CSE#90";
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk
}
};
Edit 1 :: Created a different column for score/rate as score. It is numeric.
Now my query in JS is -
but I am getting error - ValidationException: The provided key element does not match the schema
readItem_score_filter(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1"; // string
var sk = "2006#CSE"; // string
var score = 90; //number
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk,
FilterExpression:'score >=:score',
}
};
what is wrong in my FilterExpression.
Edit 2 :: Added Key condition Expression but issue still remains the same
Error: ValidationException: The provided key element does not match the schema
Here is my complete function now:
readItem_score_filter(){
console.log("inside pbro");
var table2 = "pbro";
var pk = "1"; //string
var sk = "2006#CSE"; // string
var score = 90; //number
var params2 = {
TableName: table2,
Key:{
"pk": pk,
"sk": sk,
"score": score,
KeyConditionExpression: 'pk = :pk AND sk=:sk',
FilterExpression: "score >=:score",
}
};
this.user.docClient.get(params2, function(err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
}
Screenshot of table attached incase you need to see::
If "2006#CSE#90" this is the value of sort key column then you cant do anything at Dynamodb level..
comparings like this can be done through regular expressions but DynamoDB doesn't support Regular Expressions.
you simply need to get results and then seperate these values and compare ..
Updated :- use different column for score.
And use Filter Expression to get records having rate more than 90.
I dont know python , but still am trying here
var params2 = {
TableName: "pbro",
KeyConditionExpression: "pk = :pk AND sk =:sk",
FilterExpression: "score >= :score"
};

How can I create or update a map using update expression?

I have a scenario where I want to create an item if it doesn't exist, or update an item - incrementing a total, if it already exists.
I was running into problems splitting the two operations, so I am now trying to do both using UpdateItem in a single command.
I've tried 3 different approaches none work, and they have different errors listed below, the problem it seems is creating the map and trying to update it in a single command - what should my update params look like?
Attempt one:
{
TableName: TableName,
Key: {
'key': key
},
UpdateExpression: `
ADD #total :change
, mapname.#type.#total :one
`,
ExpressionAttributeValues: {
':change': change,
':one': 1
},
ExpressionAttributeNames: {
'#type': 'dynamicstring',
'#total': 'total'
}
};
With an error of: ValidationException: The document path provided in the update expression is invalid for update
Attempt two:
{
TableName: TableName,
Key: {
"key": key
},
UpdateExpression: `
SET custommap = if_not_exists(custommap, :emptyMap)
SET #total = #total + :change,
custommap.#type.#total = custommap.#type.#total + :one
`,
ExpressionAttributeValues: {
':change': change,
':one': 1,
':emptyMap': {
'M': {
'dynamicstring': {
'M': {
'total': {
'N': 0
}
}
}
}
}
},
ExpressionAttributeNames: {
'#type': 'dynamicstring',
'#total': 'total'
}
}
With an error of: ValidationException: Invalid UpdateExpression: The "SET" section can only be used once in an update expression;
So when I use UpdateItem to create or update (increment) a map within an Item, what syntax is correct?
Thanks
SET will only stop you overwriting an attribute, not an item.
They way to achieve this is:
Use GetItem with your key to see if the item already exists
If the item exists, then do an UpdateItem and increment the counter
If the item does not exist, then use PutItem

Complex Queries in DynamoDB

I am working on an application that uses DynamoDB.
Is there a way where I can create a GSI with multiple attributes. My aim is to query the table with a query of following kind:
(attrA.val1 === someVal1 AND attrB.val2 === someVal2 AND attrC.val3 === someVal3)
OR (attrA.val4 === someVal4 AND attrB.val5 === someVal5 AND attrC.val6 === someVal6)
I am aware we can use Query when we have the Key Attribute and when Key Attribute is unknown we can use Scan operations. I am also aware of GSI if we need to query with non-key attributes. But I need some help in this scenario. Is there a way to model GSI to suit the above query.
I have the below item (i.e. data) on my Movies tables. The below query params works fine for me.
You can add the third attribute as present in the OP. It should work fine.
DynamoDB does support the complex condition on FilterExpression.
Query table based on some condition:-
var table = "Movies";
var year_val = 1991;
var title = "Movie with map attribute";
var params = {
TableName : table,
KeyConditionExpression : 'yearkey = :hkey and title = :rkey',
FilterExpression : '(records.K1 = :k1Val AND records.K2 = :k2Val) OR (records.K3 = :k3Val AND records.K4 = :k4Val)',
ExpressionAttributeValues : {
':hkey' : year_val,
':rkey' : title,
':k3Val' : 'V3',
':k4Val' : 'V4',
':k1Val' : 'V1',
':k2Val' : 'V2'
}
};
docClient.query(params, function(err, data) {
if (err) {
console.error("Unable to read item. Error JSON:", JSON.stringify(err,
null, 2));
} else {
console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
}
});
My Data:-
Result:-
GetItem succeeded: {
"Items": [
{
"title": "Movie with map attribute",
"yearkey": 1991,
"records": {
"K3": "V3",
"K4": "V4",
"K1": "V1",
"K2": "V2"
}
}
],
"Count": 1,
"ScannedCount": 1
}

dynamodb in the browser getting started

I am little confused about retrieving data from dynamodb ... connecting is not an issue cause I am getting The provided key element does not match the schema
:the example provided from AWS
var table = new AWS.DynamoDB({params: {TableName: 'MY_TABLE'}});
var key = 'UNIQUE_KEY_ID';
var itemParams = {Item: {id: {S: key}, data: {S: 'data'}}};
table.getItem({Key: {id: {S: key}}}, function(err, data) {
console.log(data.Item); // print the item data
});
in my case the unique key is "time" and what I want to do is retrieve by key (not unique)
getItem only works on the primary key. From the docs: The GetItem operation returns a set of attributes for the item with the given primary key. See docs.
To solve this, create a Global Secondary Index that has "key" as HASH and "time" as RANGE. Then do a query operation using that index as IndexName:
var params = {
IndexName: 'your-new-GSI-index',
KeyConditionExpression: '#key = :key',
ExpressionAttributeNames: { '#key': 'key },
ExpressionAttributeValues: { ':key': { S: yourKeyVar } }
}
table.query(params, callback);
(did not test this code, but should work)