I have a model event which referenceMany user.
"relations": {
"attendees": {
"type": "referencesMany",
"model": "user",
"foreignKey": "attendeeIds",
"options": {
"validate": true,
"forceId": false,
"persistent": true
}
}
How can I query event which attendees property contain a given value? attendees is an array containing userId.
For example:
Event.find({
where: {
attendees: {
contains: givenUserId
}
}
}
)
This feature is called 'Filter on level 2 properties' as referenced here and is being implemented for Memory and MongoDB connectors. It still has some issues.
For SQL connectors, this isn't supported yet and - as mentioned also inside this open discussion link - it requires some time which cannot be afforded now.
Possible work around here with regexp that would apply to the underlying JSON string and executing SQL directly via datasource.connector.execute()
Simple implementaion could be:
AnyModel.getApp((err, app) => {
if (err) {
console.log(err);
next(err);
}
// Using MySQL
const MySQL = app.dataSources.MySQL;
MySQL.connector.execute(`select * from Table where column like '%${string}%'`,
[], {}, (err, data) => {
if (err) {
console.log(err);
next(err);
}
console.log(data);
next();
});
});
Related
Is there a way of making transactWriteItem return the document it updated?
const transactionParams = {
ReturnConsumedCapacity: "INDEXES",
TransactItems: [
{
Delete: {
TableName: reactionTableName,
Key: {
"SOME_PK_",
"SOME_SK_",
},
ReturnValues: 'ALL_OLD',
},
},
{
Update: {
TableName: reviewTableName,
Key: { PK: "SOME_PK", SK: "SOME_SK" },
ReturnValues: 'ALL_OLD',
},
},
],
};
try {
const result = await docClient.transactWrite(transactionParams).promise();
} catch (error) {
context.done(error, null);
}
For example in the above code get the documents that were touched (before or after update)?
No, TransactWriteItems API does not provide the ability to return values of a modified item, however, you could obtain those values using DynamoDB Streams, otherwise you would need to default to the singleton APIs UpdateItem/DeleteItem which are not ACID compliant together.
I have a DynamoDB with nested values inside.
An Entry looks like the following:
Now I would like to scan all entries in the database to find all entries with a specific episodeGuid.
I tried this code (and some variants), but always with 0 results.
var params = {
TableName: "myTableName",
FilterExpression: "#episodeGuid = :myEpisode",
ExpressionAttributeNames: {
'#episodeGuid': 'attributes.playbackInfo.episodeGuid',
},
// ExpressionAttributeValues: { ":myEpisode": { "S": "podlove-2018-12-06t13:07:10+00:00-f8a9b2963f313e5" } }
ExpressionAttributeValues: { ":myEpisode": "podlove-2018-12-06t13:07:10+00:00-f8a9b2963f313e5" }
};
oDynamoDBClient.scan(params, async function (err, data) {
console.log('read return');
if (err) console.log(err, err.stack); // an error occurred
else {
console.log(data);
}
});
Can someone give me a hint how can I find my entries?
The filter is looking for an attribute named attributes.playbackInfo.episodeGuid as opposed to a nested attribute.
To look for a nested attribute, the expression needs to contain to ..
FilterExpression: "#attributes.#playbackInfo.#episodeGuid = :myEpisode",
ExpressionAttributeNames: {
'#attributes': 'attributes',
'#playbackInfo': 'playbackInfo',
'#episodeGuid': 'episodeGuid',
},
I am trying to search a non primary key using AWS Lambda and integrating it into the Alexa Skills Kit. I am very new to using DynamoDB and Alexa Skills Kit and I'm struggling to find any solutions to this online. The basic premise for what I am trying to do is querying the table yesno with two columns, id and message. Only looking through the message column to find a match with the text i specify in params.
Here is the Lambda code I am working with:
const AWSregion = 'eu-west-1';
const Alexa = require('alexa-sdk');
const AWS = require('aws-sdk');
//params for searching table
const params = {
TableName: 'yesno',
Key:{ "message": 'Ben Davies' }
};
AWS.config.update({
region: AWSregion
});
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
// alexa.appId = 'amzn1.echo-sdk-ams.app.1234';
// alexa.dynamoDBTableName = 'YourTableName'; // creates new table for session.attributes
alexa.registerHandlers(handlers);
alexa.execute();
};
const handlers = {
'LaunchRequest': function () {
this.response.speak('welcome to magic answers. ask me a yes or no question.').listen('try again');
this.emit(':responseReady');
},
'MyIntent': function () {
var MyQuestion = this.event.request.intent.slots.MyQuestion.value;
console.log('MyQuestion : ' + MyQuestion);
readDynamoItem(params, myResult=>{
var say = MyQuestion;
say = myResult;
say = 'you asked, ' + MyQuestion + '. I found a reckord for: ' + myResult;
this.response.speak(say).listen('try again');
this.emit(':responseReady');
});
},
'AMAZON.HelpIntent': function () {
this.response.speak('ask me a yes or no question.').listen('try again');
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak('Goodbye!');
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak('Goodbye!');
this.emit(':responseReady');
}
};
// END of Intent Handlers {} ========================================================================================
// Helper Function =================================================================================================
function readDynamoItem(params, callback) {
var AWS = require('aws-sdk');
AWS.config.update({region: AWSregion});
var dynamodb = new AWS.DynamoDB();
console.log('reading item from DynamoDB table');
dynamodb.query(params, function (err, data) {
if (err) console.log(err, err.stack); // an error occurred
else{
console.log(data); // successful response
callback(data.Item.message);
}
});
}
I know I am probably doing this completely wrong but there isn't much online for integrating DynamoDB with an Alexa Skill and the only thing i was able to find was searching by ID. This doesn't work for what i want to do without pulling all the items from the table into a map or a list, and seeing as I want to create a big database it seems quite inefficient.
On the Alexa side of things I am receiving the following service request when testing the code:
{
"session": {
"new": true,
"sessionId": "SessionId.f9558462-6db8-4bf5-84aa-22ee0920ae95",
"application": {
"applicationId": "amzn1.ask.skill.9f280bf7-d506-4d58-95e8-b9e93a66a420"
},
"attributes": {},
"user": {
"userId": "amzn1.ask.account.AF5IJBMLKNE32GEFQ5VFGVK2P4YQOLVUSA5YPY7RNEMDPKSVCBRCPWC3OBHXEXAHROBTT7FGIYA7HJW2PMEGXWHF6SQHRX3VA372OHPZZJ33K7S4K7D6V3PXYB6I72YFIQBHMJ4QGJW3NS3E2ZFY5YFSBOEFW6V2E75YAZMRQCU7MNYPJUMJSUISSUA2WF2RA3CIIDCSEY35TWI"
}
},
"request": {
"type": "IntentRequest",
"requestId": "EdwRequestId.7310073b-981a-41f8-9fa5-03d1b28c5aba",
"intent": {
"name": "MyIntent",
"slots": {
"MyQuestion": {
"name": "MyQuestion",
"value": "erere"
}
}
},
"locale": "en-US",
"timestamp": "2018-01-25T14:18:40Z"
},
"context": {
"AudioPlayer": {
"playerActivity": "IDLE"
},
"System": {
"application": {
"applicationId": "amzn1.ask.skill.9f280bf7-d506-4d58-95e8-b9e93a66a420"
},
"user": {
"userId": "amzn1.ask.account.AF5IJBMLKNE32GEFQ5VFGVK2P4YQOLVUSA5YPY7RNEMDPKSVCBRCPWC3OBHXEXAHROBTT7FGIYA7HJW2PMEGXWHF6SQHRX3VA372OHPZZJ33K7S4K7D6V3PXYB6I72YFIQBHMJ4QGJW3NS3E2ZFY5YFSBOEFW6V2E75YAZMRQCU7MNYPJUMJSUISSUA2WF2RA3CIIDCSEY35TWI"
},
"device": {
"supportedInterfaces": {}
}
}
},
"version": "1.0"
}
And I am receiving a service response error simply saying 'The response is invalid'
Any help with this would be greatly appreciated
I would like to help you in dynamo db part.
In order to access non primary key columns in dynamodb you should perform scan operation.
For your table (yesno), id is a primary key and message is an additional column.
Snippet to access non primary key column [Message]
var dynamodb = new AWS.DynamoDB();
var params = {
TableName: 'yesno',
FilterExpression: 'message = :value',
ExpressionAttributeValues: {
':value': {"S": "Ben Davies"}
}
};
dynamodb.scan(params, function(err, data) {
if (err) // an error occurred
else console.log(data); // successful response
});
Snippet to access primary key column [Id]
var docClient = new AWS.DynamoDB.DocumentClient();
//Get item by key
var params = {
TableName: 'sis_org_template',
Key: { "id": "1"}
};
docClient.get(params, function(err, data) {
if (err) // an error occurred
else console.log(data); // successful response
});
I am trying to figure out how to insert dynamic data into a dynamodb table via an API Gateway in AWS. Currently I have a dynamodb table and an API endpoint setup that accepts a POST like so.
POST https://{unique-id}.execute-api.us.east-1.amazonaws.com/notification/events
{
"reference_number": 99,
"purchase_date": "1/1/2017"
}
I've setup a body mapping template in the API gateway to massage the data into the dynamodb.
{
"TableName": "Events",
"Item": {
"reference_number": {
"N": "$input.path('$.reference_number')"
},
"purchase_date": {
"S": "$input.path('$.purchase_date')"
}
}
}
The above works and saves to the table.
Suppose I add the event hash to my json (which can change based on events).
{
"reference_number": 99,
"purchase_date": "1/1/2017",
"event": {
"name": "purchase",
"items": [1,3,6],
"info": {
"currencyID": "USD",
"countryID": "US"
}
}
}
How do I save the event attribute to a Map in dynamodb using the API Gateway Body mapping template syntax?
{
"TableName": "Events",
"Item": {
"reference_number": {
"N": "$input.path('$.reference_number')"
},
"purchase_date": {
"S": "$input.path('$.purchase_date')"
},
"event":{
"M": "$input.path('$.event')"
}
}
}
The above template gives me the following error. "Expected map or null"
It looks like DynamoDB API actually requires the value of an 'M' attribute to be a Map of String -> AttributeValue. Unfortunately you can't pass the raw JSON. You'll have to manually map the whole event object to make the DDB API happy.
http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html#DDB-Type-AttributeValue-M
One possible workaround would be to stringify the event object and write it as type S but that would of course require the reader to expect that behavior.
{
"TableName": "Events",
"Item": {
"reference_number": {
"N": "$input.path('$.reference_number')"
},
"purchase_date": {
"S": "$input.path('$.purchase_date')"
},
"event":{
"S": "$util.escapeJavaScript($input.json('$.event'))"
}
}
}
As it seems you finally did. I reckon the best option is to create a simple lambda function between you API and dynamoDB. Leaving the mapping work up to the aws-sdk.
In that case, the body mapping template in the API gateway would be as simple as this:
$input.body
And the function won't be much more complicated. I used a javascript function:
var AWS = require("aws-sdk");
var docClient = new AWS.DynamoDB.DocumentClient();
var tableName = "tableName";
var saveData = function (data) {
var params = {
TableName: tableName,
Item: data
};
docClient.put(params, function (err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
};
exports.handler = function (event) {
try {
console.log("Processing event: ", event);
saveData(event);
} catch (e) {
console.error("Processed unsuccessfully", e, e.stack);
}
};
http://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/GettingStarted.NodeJs.03.html
For my requirement (saving input body), the mapping template is
"rawdata": {
"M": $input.body
}
Note that there are no quotes for input body.
And the data should be in Dynamodb format, for eg
{"username":{"S":"Vishnu"}}
You could use js lib like dynamodb-marshaller to convert json to Dynamodb format. Hope this helps.
I have the following model in LoopBackJS:
{
"name": "member",
"base": "PersistedModel",
"properties": {
"firstName": {
"type": "string"
}
"public": {
"type": "boolean"
}
},
"relations": {
"spouse": {
"type": "hasOne",
"model": "spouse",
"foreignKey": "spouseId"
}
}
}
Now I need to modify the firstName field, so one can only see "public": true members first name and the others gets firstName: "*". The function for that I have already.
But how can I access the data on each data-access-request?
I tried it with the with the operation hook e.g. find, findOne,... but when I miss one of them some users could access the firstName.
With the remote hook it's the same.
Now I'm trying it with the connector hook:
connector.observe('after execute', function(ctx, next) {
if (ctx.model === 'familyMember') {
if (ctx.req.command === 'find') {
}
}
next();
});
For all find queries (mongodb) but there I can't access the data. Is there a way to access those data? Or is there a much better (build-in) solution for this problem?
You need to check result after each remote :
member.afterRemote('**', function(ctx, modelInstance, next) {
if (ctx.result) {
if (Array.isArray(modelInstance)) {
var answer = [];
ctx.result.forEach(function (result) {
if(result.public === false)
result.firstName = "*";
answer.push(result);
});
} else {
var answer =ctx.result;
if(answer.public === false)
answer.firstName = "*";
}
ctx.result = answer;
}
next();
});