Unable to update item on dynamoDb with aws-sdk on node.js - node.js

I'm trying to update items on my Users table. emailis my HASH key and id my RANGE
{
"accessToken": {
"M": {
"expirationDate": {
"N": "1622715427"
},
"token": {
"S": "dummy-auth-accessToken-xxx"
}
}
},
"email": {
"S": "xxx#toto.fr"
},
"firstName": {
"S": "Xxx"
},
"id": {
"S": "2"
},
"lastName": {
"S": "Yyyy"
},
"password": {
"S": "tataToto"
},
"refreshToken": {
"M": {
"expirationDate": {
"N": "1622715427"
},
"token": {
"S": "dummy-auth-refreshToken-xxx"
}
}
},
"username": {
"S": "XxxY"
}
}
I would like to update access and refresh token, so i'm doing this:
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const params = {
TableName: 'Users',
Key: { email: 'xxx#toto.fr' },
UpdateExpression: 'set #at1 = :1, #at2 = :2, #at3 = :3, #at4 = :4',
ExpressionAttributeNames: {
'#at1': 'accessToken.token',
'#at2': 'refreshToken.token',
'#at3': 'accessToken.expirationDate',
'#at4': 'refreshToken.expirationDate'
},
ExpressionAttributeValues: {
':1': 'new-dummy-auth-accessToken',
':2': 'new-dummy-auth-refreshToken',
':3': 1234567,
':4': 123456787654
},
ReturnValues: 'UPDATED_NEW'
}
dynamoDb.update(params, (err, data) => {})
but i got:
Unable to update item. Error JSON: {
"message": "The provided key element does not match the schema",
"code": "ValidationException",
"time": "2020-06-03T11:37:57.931Z",
"requestId": "PDTS2SDOEIOPMAO4VHGU6QM21JVV4KQNSO5AEMVJF66Q9ASUAAJG",
"statusCode": 400,
"retryable": false,
"retryDelay": 27.556977097280456
}
What I'm doing wrong please?

It's my bad... Need to add HASH AND RANGE key on params object
Key: {
id: "2"
email: 'xxx#toto.fr'
}
and my expressions is not good but i know how fix it :)
Ty to read x)

Related

Filter data using nodejs and elasticsearch

I'm currently facing an issue with my datatable implemented in ReactJS. I'm retrieving data from elasticsearch and populating the datatable with it. The data retrieval process works fine without the filter applied, however, when I apply filters to the data, the datatable remains empty, even though the data _source has matching records.
The structure of the parameters I am sending is as follows:
{
pageIndex: 1,
pageSize: 10,
sort: { order: '', key: '' },
query: '',
filterData: {
analysis: [ '0', '1', '2', '3' ],
threat_level_id: [ '1', '2', '3', '4' ],
}
}
EndPoint:
POST /api/v1/events/public/list
Controller:
exports.getPublicEvents = async (req, res) => {
try {
client.ping()
const { pageIndex, pageSize, sort, query, filterData } = req.body
let esQuery = {
index: 'ns_*',
body: {
query: {
bool: {
must: [
{
match_all: {},
},
],
filter: [],
},
},
from: (pageIndex - 1) * pageSize,
size: pageSize,
},
}
if (query) {
esQuery.body.query.bool.must = [
{
match: {
'Event.info': {
query: query,
fuzziness: 'AUTO',
},
},
},
]
}
if (filterData.analysis.length > 0) {
esQuery.body.query.bool.filter.push({
terms: {
'Event.analysis': filterData.analysis,
},
})
}
if (filterData.threat_level_id.length > 0) {
esQuery.body.query.bool.filter.push({
terms: {
'Event.threat_level_id': filterData.threat_level_id,
},
})
}
let esResponse = await client.search(esQuery)
let data = esResponse.hits.hits.map((hit) => hit._source)
let total = esResponse.hits.total.value
res.status(200).json({
status: 'success',
data: data,
total: total,
})
} catch (error) {
res.status(500).json({
error: 'Error connecting to Elasticsearch',
errorMessage: error.message,
})
}
}
The controller below is without filters and it works just fine.
exports.getPublicEvents = async (req, res) => {
try {
client.ping()
const { pageIndex, pageSize, sort, query } = req.body
let esQuery = {
index: 'ns_*',
body: {
query: {
match_all: {},
},
from: (pageIndex - 1) * pageSize,
size: pageSize,
},
}
if (query) {
esQuery.body.query = {
match: {
'Event.info': {
query: query,
fuzziness: 'AUTO',
},
},
}
}
let esResponse = await client.search(esQuery)
let data = esResponse.hits.hits.map((hit) => hit._source)
let total = esResponse.hits.total.value
res.status(200).json({
status: 'success',
data: data,
total: total,
})
} catch (error) {
res.status(500).json({
error: 'Error connecting to Elasticsearch',
errorMessage: error.message,
})
}
}
ElasticSearech version: 7.17.8
Result of: console.log(JSON.stringify(esQuery))
{
"index": "INDEX_NAME",
"body": {
"query": {
"bool": {
"must": [{ "match_all": {} }],
"filter": [
{ "terms": { "Event.analysis": ["0", "1", "2"] } },
{ "terms": { "Event.threat_level_id": ["1", "2", "3", "4"] } }
]
}
},
"from": 0,
"size": 10
}
}
Data in elascticsearch schema
{
"#version": "1",
"#timestamp": "2023-02-01T14:43:09.997Z",
"Event": {
"info": ".......................",
"description": ".......................",
"analysis": 0,
"threat_level_id": "4",
"created_at": 1516566351,
"uuid": "5a64f74f0e543738c12bc973322",
"updated_at": 1675262417
}
}
Index Mapping
{
"index_patterns": ["INDEX_NAME"],
"template": "TEMPLATE_NAME",
"settings": {
"number_of_replicas": 0,
"index.mapping.nested_objects.limit": 10000000
},
"mappings": {
"dynamic": false,
"properties": {
"#timestamp": {
"type": "date"
},
"Event": {
"type": "nested",
"properties": {
"date_occured": {
"type": "date"
},
"threat_level_id": {
"type": "integer"
},
"description": {
"type": "text"
},
"is_shared": {
"type": "boolean"
},
"analysis": {
"type": "integer"
},
"uuid": {
"type": "text"
},
"created_at": {
"type": "date"
},
"info": {
"type": "text"
},
"shared_with": {
"type": "nested",
"properties": {
"_id": {
"type": "text"
}
}
},
"updated_at": {
"type": "date"
},
"author": {
"type": "text"
},
"Attributes": {
"type": "nested",
"properties": {
"data": {
"type": "text"
},
"type": {
"type": "text"
},
"uuid": {
"type": "text"
},
"comment": {
"type": "text"
},
"category": {
"type": "text"
},
"value": {
"type": "text"
},
"timestamp": {
"type": "date"
}
}
},
"organisation": {
"type": "nested",
"properties": {
"name": {
"type": "text"
},
"uuid": {
"type": "text"
}
}
},
"Tags": {
"type": "nested",
"properties": {
"color": {
"type": "text"
},
"name": {
"type": "text"
}
}
},
"TLP": {
"type": "nested",
"properties": {
"color": {
"type": "text"
},
"name": {
"type": "text"
}
}
}
}
}
}
}
}
Event is a nested field, so you need to use nested queries, like this:
{
"index": "INDEX_NAME",
"body": {
"query": {
"bool": {
"must": [{ "match_all": {} }],
"filter": [
{
"nested": {
"path": "Event",
"query": {"terms": { "Event.analysis": ["0", "1", "2"] }}
}
},
{
"nested": {
"path": "Event",
"query": {"terms": { "Event.threat_level_id": ["1", "2", "3", "4"] }}
}
}
]
}
},
"from": 0,
"size": 10
}
}

Scan for a nested Map inside a List that don't exist

I would like some help with structuring a scan via AWS CLI to get results where the "on_demand" map does not exist. The "on_demand" map is nested in other parent maps [0 , 1, 2...]. Which in turn are in the playlist List.
The conditions for the scan would be where is_offsite = true, video_type = OFFSITE and of course the troublesome condition where the "on_demand" map does not exist.
This is my table structure.
{
"Items": [
{
"playlist": {
"L": [
{
"M": {
"duration": {
"N": "46"
},
"on_demand": {
"M": {
"bucket": {
"S": "s3 Bucket"
},
"key": {
"S": "bucket url to video file"
}
}
},
"download": {
"M": {
"bucket": {
"S": "s3 bucket"
},
"key": {
"S": "bucket url to video file"
}
}
},
"status": {
"S": "on_demand"
}
},
"M": {
"duration": {
"N": "60"
},
"on_demand": {
"M": {
"bucket": {
"S": "s3 Bucket"
},
"key": {
"S": "bucket url to video file"
}
}
},
"download": {
"M": {
"bucket": {
"S": "s3 bucket"
},
"key": {
"S": "bucket url to video file"
}
}
},
"status": {
"S": "on_demand"
}
}
}
]
},
"video_type": {
"S": "OFFSITE"
},
"id": {
"S": "random hash id"
},
"is_offsite": {
"BOOL": true
},
}
]
}
Any assistance will be much appreciated.
This was accomplished by using the following:
aws dynamodb scan \
--table-name table-name \
--projection-expression "id" \
--filter-expression 'is_offsite = :os AND video_type = :vt AND attribute_not_exists(playlist[0].on_demand)' \
--expression-attribute-values '{":os": { "BOOL": true},":vt": {"S": "OFFSITE"}}'

Elasticsearch Node.js client: delete a nested element from a object

I have a object like bellow
"_source": {
"name": "capsicum",
"id": "60f759b934e43100195c6142",
"userId": "60f7209ecdb2c0001935fa8f",
"version": 1,
"tags": [
{
"name": "fruit",
"id": "60f75990be3b530019062790",
"group": "location"
},
{
"name": "green",
"id": "60f75990be3b530019062766",
"group": "food"
},
{
"name": "red",
"id": "60f75990be3b530019062722",
"group": "food"
},
{
"name": "vegetable",
"id": "60f75990be3b53001906272d",
"group": "food"
}
]
}
how can I delete one element from tags, add an element in tags, in separate api calls.
I tried bellow code for deleting but not working
elasticClient.updateByQuery(
{
index: ElasticIndexs.Products,
body: {
script: {
source: `ctx._source.tags.removeIf(a -> a.id == params.id)`,
params: {
id: product.tag.id,
},
},
query: {
match: {
id: product.id,
},
},
},
},
function (error, response) {
console.log(response);
}
);
for adding:
await elasticWrapper.client.update({
index: ElasticIndexs.Products,
id: data.id,
body: {
script: {
inline: 'ctx._source.tags.add(params.tag)',
// lang: 'painless',
params: {
tag: data.tag,
},
},
},
});
for deleting:
await elasticWrapper.client.update({
index: ElasticIndexs.Products,
id: data.id,
body: {
script: {
inline: `for (int i = 0; i < ctx._source.tags.size();
i++){if(ctx._source.tags[i].id == params.id){ctx._source.tags.remove(i);}}`,
params: {
id: data.tag.id,
},
},
},
});

AWS SDK issues with DynamoDB and putItem

I am trying to use the aws-sdk to interact with AWS' dynamodb
Here is my code:
DynamoDB.putItem({
"TableName": tblName,
"Item": {
"UserId": { "N": obj.user_id.toString() },
"Identifier": { "S": obj.identifier },
"ReferralToken": { "S": obj.referral_token },
"CampaignId": { "N": obj.campaign_id.toString() },
"FirstName": { "S": obj.first_name },
"LastName": { "S": obj.last_name },
"Gender": { "S": obj.gender },
"BirthDate": { "S": obj.birthdate },
"Username": { "S": obj.username },
"MobileNumber": { "S": obj.mobile_number },
"PostalCodeText": { "S": obj.postal_code_text },
"Classification": { "S": obj.classification },
"DeliveryEmail": { "S": obj.delivery_email.toString() },
"DeliverySMS": { "S": obj.delivery_sms.toString() }
}
}, function (err, data) {
console.log(err);
console.log(data);
});
The error I am receiving is
{ [ValidationException: Supplied AttributeValue is empty, must contain exactly one of the supported datatypes]
message: 'Supplied AttributeValue is empty, must contain exactly one of the supported datatypes',
code: 'ValidationException',
time: Fri Oct 10 2014 10:15:25 GMT-0500 (CDT),
statusCode: 400,
retryable: false }
Not sure what I am doing wrong
According to the Put Item documentation,
When you add an item, the primary key attribute(s) are the only required attributes. Attribute values cannot be null. String and Binary type attributes must have lengths greater than zero. Set type attributes cannot be empty. Requests with empty values will be rejected with a ValidationException exception.
So make sure all values are non-null, and that all string lengths are greater than zero.
In my case , I got the same issue because of invalid parameter sends from mapping template.
#set($inputRoot = $input.path('$'))
{
"userId": "$input.params('userId')",
"userEmail": "$input.params('userEmail')",
"userName": "$input.params('userName')",
"userPassword": "$input.params('userPassword')"
}
Here I sent extra parameter userId , that's why error occurred .
So please check your mapping template , May be possible your doing same .

Scanning DynamoDB with ConditionalOperator set to OR is still performing an AND

Per the API Docs I've got the following scan params:
var params = {
"TableName": "MyTable",
"ScanFilter": {
"id": {
"AttributeValueList": [
{
"S": "ID-A"
},
{
"S": "ID-D"
}
],
"ComparisonOperator": "IN"
},
"facilityName": {
"AttributeValueList": [
{
"S": "Name A"
}
],
"ComparisonOperator": "IN"
}
},
"ConditionalOperator": "OR"
};
dynamo.scan(params, function (err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(JSON.stringify(data, null, 2));
}
});
Regardless of the value in the ConditionalOperator field, the scan always performs an AND. What am I doing wrong?
I would expect with the OR to see ID-A, ID-C AND ID-D. I only ever get ID-D.
If I do a plain or scan, with no ScanFilter setup this is the data:
{
"Count": 4,
"ScannedCount": 4,
"Items": [
{
"facilityName": {
"S": "Name B"
},
"id": {
"S": "ID-A"
}
},
{
"facilityName": {
"S": "Name B"
},
"id": {
"S": "ID-B"
}
},
{
"facilityName": {
"S": "Name A"
},
"id": {
"S": "ID-C"
}
},
{
"facilityName": {
"S": "Name A"
},
"id": {
"S": "ID-D"
}
}
]
}
I am able to use the Java SDK to do what you want:
public static void test() {
ScanRequest scanRequest = new ScanRequest("MyTable");
scanRequest.setConditionalOperator(ConditionalOperator.OR);
Map<String, Condition> scanFilter = new HashMap<String, Condition>();
Condition idFilter = new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(new AttributeValue("ID-A"), new AttributeValue("ID-D"));
Condition facilityNameFilter = new Condition().withComparisonOperator(ComparisonOperator.IN).withAttributeValueList(new AttributeValue("Name A"));
scanFilter.put("id", idFilter);
scanFilter.put("facilityName", facilityNameFilter);
scanRequest.setScanFilter(scanFilter);
ScanResult scanResult = dynamo.scan(scanRequest);
for(Map<String, AttributeValue> item : scanResult.getItems()) {
System.out.println(item);
}
}
I am not familar with the JS SDK that you are using. But your code seems OK.
When looking at the js doc, I notcied that ConditionalOperator is introduced in the 2012 version and it is not available in the 2011 version.
Can you verify that you are using the 12 version?

Resources