Dynamoose TypeScript ValidationException: The number of conditions on the keys is invalid when using .get() - dynamoose

Given the below dynamodb schema for creating the table:
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
},
{
"AttributeName": "name",
"KeyType": "RANGE"
}
],
and dynamoose schema in code:
new dynamoose.Schema({
id: {
type: String,
},
name: {
type: String,
},
Was seeing ValidationException: The number of conditions on the keys is invalid error when using repository.get()

The solution: Need to specify the range key in dynamoose schema.
id: {
type: String,
hashKey: true,
},
name: {
type: String,
rangeKey: true,
},

Related

dynamoose search using GSI returns Index can't be found for query

Here's my dynamoose schema for table seller
const schema = new dynamoose.Schema({
PK: {
type: String, //ni letak emel.toLowerCase() + #main/business/delivery/ehailing
hashKey: true,
},
SK: {
type: String,
rangeKey: true,
"index": { //utk 'auto' display kedai bila user ada kat location tu
"name": "SKIndex",
"global": true,
"rangeKey": "location"
}
},
"location": String,
}, {
"saveUnknown": true,
"timestamps": true
});
As you can see above, I created a GSI with the SK as the hashkey named SKIndex and having location as the rangeKey. So I tried to perform the query below
var SKIndex_search = "some value"
var locality = "some value too"
var filter = new dynamoose.Condition().where("SKIndex").eq(SKIndex_search).filter("location").beginsWith(locality);
var getResult = await Seller.query(filter).exec()
but it will always return the error "InvalidParameter: Index can't be found for query."
==============
When running this query Seller.query(SKIndex_search).using("SKIndex").filter("location").beginsWith(locality).exec()
It will display the error message ValidationException: Query condition missed key schema element
Full error log:
aws:dynamodb:describeTable:response - {
"Table": {
"AttributeDefinitions": [
{
"AttributeName": "PK",
"AttributeType": "S"
},
{
"AttributeName": "SK",
"AttributeType": "S"
},
{
"AttributeName": "location",
"AttributeType": "S"
}
],
"TableName": "earthlings_seller",
"KeySchema": [
{
"AttributeName": "PK",
"KeyType": "HASH"
},
{
"AttributeName": "SK",
"KeyType": "RANGE"
}
],
"TableStatus": "ACTIVE",
"CreationDateTime": "2021-06-26T20:50:13.233Z",
"ProvisionedThroughput": {
"LastIncreaseDateTime": "1970-01-01T00:00:00.000Z",
"LastDecreaseDateTime": "1970-01-01T00:00:00.000Z",
"NumberOfDecreasesToday": 0,
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"TableSizeBytes": 312,
"ItemCount": 1,
"TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/earthlings_seller",
"GlobalSecondaryIndexes": [
{
"IndexName": "SKIndex",
"KeySchema": [
{
"AttributeName": "SK",
"KeyType": "HASH"
},
{
"AttributeName": "location",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "ALL"
},
"IndexStatus": "ACTIVE",
"ProvisionedThroughput": {
"ReadCapacityUnits": 1,
"WriteCapacityUnits": 1
},
"IndexSizeBytes": 312,
"ItemCount": 1,
"IndexArn": "arn:aws:dynamodb:ddblocal:000000000000:table/earthlings_seller/index/SKIndex"
}
]
}
}
aws:dynamodb:query:request - {
"ExpressionAttributeNames": {
"#qra": "location"
},
"ExpressionAttributeValues": {
":qrv": {
"S": "nilai"
}
},
"TableName": "earthlings_seller",
"IndexName": "SKIndex",
"KeyConditionExpression": "begins_with (#qra, :qrv)"
}
As descrribed in the Dynamoose documentation, where takes in a key attribute. This key represents an attribute name (SK), not an index name (SKIndex).
Changing your code to the following should work.
new dynamoose.Condition().where("SK").eq(SKIndex_search).filter("location").beginsWith(locality);
You can also use the using function to manually set a specific index to run your query on. However this is optional. Dynamoose will use a system to look through your indexes and pick one that best matches your query you are making.

Updating a table in DynamoDb using FilterExpression

So I have this JSON object
{
"id": "c66c588e",
"players": {
"M2cfydGooAMCLpQ=": {},
"ygjjgy7678": {}
}
}
For a given player Id, I want to update that particular object, so it becomes
{
"id": "c66c588e",
"players": {
"M2cfydGooAMCLpQ=": {
"cards": [
{
"cardId": "id1",
"cardTitle": "title here"
}
]
},
"ygjjgy7678": {}
}
}
This is the query I have
const params = {
TableName: process.env.DYNAMODB_GAMES_TABLE,
Key: {
id: gameId
},
UpdateExpression: 'set players.#player = list_append(if_not_exists(#cards, :empty_list), :card)',
ExpressionAttributeNames: {
'#cards': 'cards',
'#player': playerId
},
ExpressionAttributeValues: {
':card': [{
"cardId": cardId,
"cardTitle": cardTitle,
"pun": pun
}],
':empty_list': []
},
ReturnValues: "ALL_NEW"
};
But I get this error
{
"message": "The document path provided in the update expression is invalid for update",
"code": "ValidationException",
"time": "2020-05-21T00:50:32.236Z",
"requestId": "HLJJA2QQ2POAQEAJUD3143T6PJVV4KQNSO5AEMVJF66Q9ASUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 38.70011614235671
}
I cannot seem to figure out how to update a particular player.
I think creating a new Index will result in additional AWS costs which I want to avoid.
I figured it out.
The key should be a valid key which you can access by obj.key and not obj[key]
Then this query will work
const params = {
TableName: process.env.DYNAMODB_GAMES_TABLE,
Key: {
id: gameId
},
UpdateExpression: 'set players.#player = list_append(if_not_exists(#cards, :empty_list), :card)',
ExpressionAttributeNames: {
'#cards': 'cards',
'#player': playerId
},
ExpressionAttributeValues: {
':card': [{
"cardId": cardId,
"cardTitle": cardTitle,
"pun": pun
}],
':empty_list': []
},
ReturnValues: "ALL_NEW"
};

Error creating table in local DynamoDB

I have downloaded local version for Amazon DynamoDB. I am trying to create a table using shell. When I run the code from shell it gives me an error:
"message":"The security token included in the request is invalid."
"code":"UnrecognizedClientException"
"time":"2017-04-27T12:50:35.880Z"
"statusCode":400
"retryable":false
Create code is:
var dynamodb = new AWS.DynamoDB();
var params = {
"AttributeDefinitions": [
{
"AttributeName": "UserId",
"AttributeType": "N"
},
{
"AttributeName": "FirstName",
"AttributeType": "S"
},
{
"AttributeName": "LastName",
"AttributeType": "S"
},
{
"AttributeName": "CellPhoneNumber",
"AttributeType": "N"
}
],
"TableName": "Users",
"KeySchema": [
{
"AttributeName": "UserId",
"KeyType": "HASH"
},
{
"AttributeName": "CellPhoneNumber",
"KeyType": "RANGE"
}
],
"LocalSecondaryIndexes": [
{
"IndexName": "UserIndex",
"KeySchema": [
{
"AttributeName": "UserId",
"KeyType": "HASH"
},
{
"AttributeName": "CellPhoneNumber",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "KEYS_ONLY"
}
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
dynamodb.createTable(params, function(err, data) {
if (err) ppJson(err); // an error occurred
else ppJson(data); // successful response
});
How do I create a table in local DynamoDB? Do I need to create a DB first? I am asking this because I have always worked on SQL and this is the first time I am using NoSQL
No need to create database. Just need to create table.
Use the below configuration for local dynamodb. The endpoint URL is important. The other attributes are dummy values (i.e. it can be any values).
var creds = new AWS.Credentials('akid', 'secret', 'session');
AWS.config.update({
region: "us-west-2",
endpoint: "http://localhost:8000",
credentials : creds
});
Also, no need to define all the attributes while creating the table. Only key attributes need to be defined. Otherwise, you will get error.
Full code to create table (should be executed on http://localhost:8000/shell/):-
var dynamodb = new AWS.DynamoDB({
region: 'us-east-1',
endpoint: "http://localhost:8000"
});
var tableName = "Movies";
var params = {
"AttributeDefinitions": [
{
"AttributeName": "UserId",
"AttributeType": "N"
},
{
"AttributeName": "CellPhoneNumber",
"AttributeType": "N"
}
],
"TableName": "PBUsers",
"KeySchema": [
{
"AttributeName": "UserId",
"KeyType": "HASH"
},
{
"AttributeName": "CellPhoneNumber",
"KeyType": "RANGE"
}
],
"LocalSecondaryIndexes": [
{
"IndexName": "UserIndex",
"KeySchema": [
{
"AttributeName": "UserId",
"KeyType": "HASH"
},
{
"AttributeName": "CellPhoneNumber",
"KeyType": "RANGE"
}
],
"Projection": {
"ProjectionType": "KEYS_ONLY"
}
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
dynamodb.createTable(params, function(err, data) {
if (err) {
if (err.code === "ResourceInUseException" && err.message === "Cannot create preexisting table") {
console.log("message ====>" + err.message);
} else {
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
}
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
var params = {
TableName: 'student',
KeySchema: [
{
AttributeName: 'sid',
KeyType: 'HASH',
},
],
AttributeDefinitions: [
{
AttributeName: 'sid',
AttributeType: 'N',
},
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10,
},
};
dynamodb.createTable(params, function(err, data) {
if (err) ppJson(err); // an error occurred
else ppJson(data); // successful response
});
You need to also install aws-amplify cli locally as well before you can create a local DynamoDB table.
npm install -g #aws-amplify/cli

How to get documents from MiniMongo where value is nested?

I have a Meteor application with a Mongo database containing documents with the following structure:
_id: "1234567890",
blocks: [{
type: "block",
block_id: "foobar",
items: [
{
type: "sub",
sub_id: "111",
items: [
{
type: "question",
question_id: "aaa"
},
{
type: "question",
question_id: "bbb"
}
]
},
{
type: "question",
question_id: "aaa"
}
]
}]
I want to be able to find all the questions with a question_id of 'aaa'. So far I have tried these queries, but am struggling to return any results:
questions = MyColl.find({
$or: [{
blocks: {
items: {
$elemMatch: {question_id: 'aaa'}
}
}
},{
blocks: {
items: {
type: "sub",
items: {
question_id: 'aaa'
}
}
}
}]
}).count();
Any ideas?
This is how I mananged it:
questions = MyColl.find({
$or: [{
'blocks.items': {
$elemMatch: {question_id: 'aaa'}
}
},{
'blocks.items.items': {
$elemMatch: {question_id: 'aaa'}
}
}]
}).count();

PartialShardFailureException when trying to filter by GeoDistance (foselasticaBundle Symfony2)

For a few days my elastica query doesn't work anymore. I don't have problem to populate and if i remove the GeoDistance part the request is been executed and i get results. Currently, in the trace, I got the following message:
"message": "1",
"class": "Elastica\\Exception\\PartialShardFailureException",
"trace": [
{
"namespace": "",
"short_class": "",
"class": "",
"type": "",
"function": "",
"file": "/Applications/MAMP/htdocs/GTAB/what2days/api/vendor/ruflin/elastica/lib/Elastica/Transport/Http.php",
"line": 150,
"args": []
}
It means nothing to me so I just made a var_export of $shardsStatistics variable and I get that:
array (
'total' => 6,
'successful' => 5,
'failed' => 1,
'failures' =>
array (
0 =>
array (
'index' => '.marvel-2014.09.16',
'shard' => 0,
'status' => 400,
'reason' => 'SearchParseException[[.marvel-2014.09.16][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{"query":{"filtered":{"query":{"bool":{"must":[{"term":{"online":{"value":1}}}]}},"filter":{"bool":{"must":[{"geo_distance":{"distance":"100mi","location.latlon":{"lat":48.891773,"lon":2.3379156}}}]}}}}}},"size":"100"}]]]; nested: QueryParsingException[[.marvel-2014.09.16] failed to find geo_point field [location.latlon]]; ',
),
),
)
The error finish by " failed to find geo_point field [location.latlon]] ". I don't know why it doesn't work because when i check the _mapping the geo_point exists and i didn't make a mistake with the name of the property.
location: {
properties: {
latitude: {
type: "float",
store: true
},
latlon: {
type: "geo_point",
store: true,
lat_lon: true
},
longitude: {
type: "float",
store: true
}
}
},
And this is the way i set fos_elastica
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
search:
finder: ~
types:
mytype:
mappings:
title:
type: string
online:
type: integer
information: ~
location:
type: object
properties:
longitude:
type: float
latlon:
type: geo_point
lat_lon: true
boost: 10
persistence:
driver: orm
model: API\Rest\v1\MyBundle\Entity\MyEntity
provider: ~
listener: ~
finder: ~
repository: API\Rest\v1\MyBundle\Repository\MyRepository
When i make a kopf request with the query value (see following query) retrieved by $query->getQuery() i get a correct result.
{
"query": {
"filtered": {
"query": {
"bool": {
"must": [
{
"term": {
"online": {
"value": 1
}
}
}
]
}
},
"filter": {
"bool": {
"must": [
{
"geo_distance": {
"distance": "1mi",
"location.latlon": {
"lat": 48.891773,
"lon": 2.3379156
}
}
}
]
}
}
}
}
}
I don't know what to do. I was on 3.0.*#alpha version and now I'm trying the dev-master. I hope someone will help me find what goes wrong.
When I make a var_export in the method getData from Elastica/Response.php I have the failure I explained earlier and I also have 1 hit (the one Iwant to get).
I finally found the solution.
I had to add an index_name and tell \Elastica\Search to addIndex('new_index') and addType('specific type')
I thought the search will automatically get the correct index because I was using a specific repository but I was wrong.

Resources