How to query DynamoDB in AWS using a number partition key - json

I'm currently having trouble querying a DynamoDB table where the partition key, id, is of type number. This is for a wider project for my own Alexa Skill on AWS. My skill will take as input from the user, a unique id value, which is of slot type AMAZON.NUMBER.
I've looked at the documentation for query and nothing I've tried worked so I decided to start from scratch to a template.
Again, I am just trying to query a table for data based on a partition key called "id" that has a numeric value. The Code below is what I have managed to narrow down as the source of the error.
var params = {
TableName : "QueryTestTable",
KeyConditionExpression: "#pkey = :value",
ExpressionAttributeNames:{
"#pkey": "id"
},
ExpressionAttributeValues: {
":value": idNumber
}
};
return docClient.query(params, function(err,data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
} else {
console.log("Query succeeded.");
console.log("data = " + JSON.stringify(data,null,2));
data.Items.forEach(function(item) {
console.log(" -", item.id + ": " + item.firstName);
results += item.id + " has name " +item.firstName + " " + item.lastName + ".\n";
});
}
if (results)
speakOutput = results;
else
speakOutput = "Sorry, no result for " + idNumber +" was found in the database.";
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt()
.withSimpleCard(SKILL_NAME, speakOutput) //added to generate video output.
.getResponse();
})
I'm just using a simplified version of my table for now. But the above code snippet. For some reason, It keeps skipping to the no entries found in the database statement.

Related

Query is working on phpmyadmin but not in express

I have a problem with a MySQL query, I'm making a controller where I need a filter on the front (React). The controller is made with params inside the route, but is not working when I try to test it with Postman, but if I make the same exact query on phpmyadmin works perfectly.
Controller:
let { tabla, nameUno, fechaIni, fechaFin, nameDos, nameTres, nameCuatro } =
req.params;
conn.query(
// SELECT * FROM tyt_finan WHERE tf_fecha_r BETWEEN '2022-05-31' AND '2022-06-01' AND tf_city IN ('Bogota') AND tf_estado = 'Pendiente' AND tf_campana = 'IN'
"SELECT * FROM " +
tabla +
" WHERE " +
nameUno +
" BETWEEN " +
fechaIni +
" AND " +
fechaFin +
" AND " +
nameDos +
" IN ('') AND " +
nameTres +
" = ? AND " +
nameCuatro +
" = ?",
[req.params.value1, req.params.value2, req.params.value3],
Routes
routes.get(
"/searchAll/:tabla/:nameUno/:fechaIni/:fechaFin/:nameDos/:value1/:nameTres/:value2/:nameCuatro/:value3",
defaultController.searchAll
);
And this is the GET petition that I'm sending on Postman:
http://localhost:9000/searchAll/tyt_finan/tf_fecha_r/'2022-05-31'/'2022-06-01'/tf_city/'Bogota','Barranquilla'/tf_estado/'Pendiente'/tf_campana/'IN'
Use parameters for the variables. It's also easier to use a template literal than concatenation to construct the SQL string with variables for the table and column names.
You also had more values in your parameters array than ? in the SQL. I've replaced IN ('') with = ? to use value1 there.
let {tabla, nameUno, fechaIni, fechaFin, nameDos, value1, nameTres, value2, nameCuatro, value3} = req.params;
conn.query(
`SELECT *
FROM ${tabla}
WHERE ${nameUno} BETWEEN ? AND ?
AND ${nameDos} = ?
AND ${nameTres} = ?
AND ${nameCuatro} = ?`, [fetchaIni, fechaFin, value1, value2, value3], (err, res) => {
if (!err) {
console.log(res);
}
});

Determine which PropertyInfos of a generic TEntity are primary keys via reflection

I am writing a MySQL INSERT ... ON DUPLICATE KEY UPDATE implementation via a raw SQL command in EF Core 2.0. I am very close to a working solution, but the only problem that I have is determining which PropertyInfos read via reflection are primary keys. In the CreateUpdates() method below, how can I filter primary keys out from columnProperties so they are not a part of the update SQL statement?
I have tried using EntityFramework.PrimaryKey
, but I cannot seem to get it to work with generics (TEntity).
I have included all of my relevant code, but the piece I am focused on in this question is the TODO in the last method, CreateUpdates().
private static void InsertOnDuplicateKeyUpdate<TEntity>(DbContext dbContext) where TEntity : class
{
var columnProperties = GetColumnPropertiesLessBaseEntityTimestamps<TEntity>();
var tableName = GetTableName<TEntity>();
var columns = string.Join(", ", columnProperties.Select(x => x.Name));
var values = CreateValues<TEntity>(columnProperties);
var updates = CreateUpdates(columnProperties);
var rawSqlString = "INSERT INTO " + tableName + " (" + columns + ") VALUES " + values +
" ON DUPLICATE KEY UPDATE " + updates;
dbContext.Set<TEntity>().FromSql(rawSqlString);
dbContext.SaveChanges();
}
private static string GetTableName<TEntity>()
{
return typeof(TEntity).Name.Pluralize().ToLower();
}
private static List<PropertyInfo> GetColumnPropertiesLessBaseEntityTimestamps<TEntity>()
{
return typeof(TEntity).GetProperties().Where(x =>
x.PropertyType.Namespace != "System.Collections.Generic" &&
!new List<string> {"CreatedDateUtc", "ModifiedDateUtc"}.Contains(x.Name)).ToList();
}
private static string CreateValues<TEntity>(IReadOnlyCollection<PropertyInfo> columnProperties)
{
return GetSeedRows<TEntity>().Select(row => CreateRowValues(columnProperties, row)).Aggregate("",
(current, rowValues) => current == "" ? rowValues : current + ", " + rowValues);
}
private static string CreateRowValues<TEntity>(IEnumerable<PropertyInfo> columnProperties, TEntity row)
{
return (from property in columnProperties
let value = row.GetType().GetProperty(property.Name).GetValue(row)
select WrapStringPropertyValueInSingleQuotes(property, value)).Aggregate("",
(current, value) => current == "" ? "(" + value : current + ", " + value) + ")";
}
private static object WrapStringPropertyValueInSingleQuotes(PropertyInfo property, object value)
{
if (property.PropertyType == typeof(string))
value = "'" + value + "'";
return value;
}
private static string CreateUpdates(IEnumerable<PropertyInfo> columnProperties)
{
//TODO: filter out primary keys from columnProperties
return columnProperties.Select(property => property.Name).Aggregate("", (current, column) => current == ""
? column + " = VALUES(" + column + ")"
: current + ", " + column + " = VALUES(" + column + ")");
}
In ef-core it has become much easier to retrieve meta data from the mapping model. You can get the PropertyInfos of the primary key by this line:
var keyPropertyInfos = dbContext.Model.FindEntityType(typeof(TEntity))
.FindPrimaryKey()
.Properties
.Select(p => p.PropertyInfo);
By the way, you can get all (mapped) properties by replacing FindPrimaryKey().Properties by GetProperties();

Calculated Fields with nestTables Option for MySQL Query in NodeJS

I'm using the 'nestTables' option in the code below to separate the data returned from an SQL query into their respective tables. I am also including a calculated field in my query that I would like to include in the primary table.
As an example, I am executing the following route:
router.route('/person/:personId').get(function(req,res){
var person_id = req.params.personId;
db.getConnection(function(err, connection) {
if (err) {
return res.status(503).send({ result: false, error: 'CONNECTION error: ' + err.code});
} else {
var sqlString='SELECT *, someField - 1 as calculated FROM person LEFT JOIN person_status ON person.id = person_status.person_id WHERE person.id = ' + person_id;
var options={sql:sqlString,nestTables:true};
connection.query(options, function(error, rows, fields) {
connection.release();
var nestingOptions = [
{tableName: 'person', pkey:'id'},
{tableName: 'person_status', pkey:'id', fkeys:[{table:'person',col:'person_id'}]}
];
if (error) {
return res.status(500).send({ result: false, error: 'QUERY ERROR: ' + error.code});
} else {
return res.status(200).send(rows);
}
});
}
});
});
and I am receiving the following JSON Response:
[
{
"person": {
"id": 1,
other person data . . .
"person_status": [
{
"id": 3,
other data . . .
}
]
},
"person_status": {
"id": 3,
other data . . .
},
"": {
"calculated": 0
}
}
]
Ideally, I would like to include the calculated field into the person subgroup as shown below:
[
{
"person": {
"id": 1,
"calculated": 0
other person data . . .
"person_status": [
{
"id": 3,
other data . . .
}
]
},
"person_status": {
"id": 3,
other data . . .
}
}
]
Is there any way that I can include the calculated field into the person table, or is there a better solution that fits this problem?
Thanks in advance!
I see two options to solve this, one dirty way using SQL:
var sqlString = 'SELECT *, someField - 1 as calculated FROM person WHERE person.id=?';
sqlString = 'SELECT * FROM (' + sqlString + ') as person';
sqlString += ' LEFT JOIN person_status ON person.id = person_status.person_id';
var options={sql:sqlString, nestTables:true};
connection.query(options, [person_id], function(error, rows, fields) {
and the obvious solution using js:
var sqlString = 'SELECT *, someField - 1 as calculated FROM person LEFT JOIN person_status ON person.id = person_status.person_id WHERE person.id=?';
var options = {sql:sqlString, nestTables:true};
connection.query(options, [person_id], function(error, rows, fields) {
rows.forEach(function(row) {
row.person.calculated = row[''].calculated;
delete row[''];
});
I don't think there is a more pleasant solution for this. I even checked if there is a possibility to trick the FieldPacket or RowDataPacket parser but didn't see a way to fake a table name (without monkey patching the mysql driver).

Make query after query with nodejs and sequelize

I want to make a query after another query in node.js with sequqlize. Second query iterate ower the first elements query result.
The code:
exports.index = function(req, res) {
sqldb.sequelize.query("select * from food", {type: sqldb.sequelize.QueryTypes.SELECT})
.then(function (food) {
for (var i = food.length; i--;) {
sqldb.sequelize.query("select i.name_ingredient " +
"from food_incredients as fi, " +
"ingredients as i " +
"where fi.food_id = " + food[i].id + " and " +
"i.id = fi.ingredient_id;",
{type: sqldb.sequelize.QueryTypes.SELECT}).then(function (ingredients) {
food[i]["ingredients"] = ingredients;
});
}
res.status(200).json(food);
}
);
At the line when I try to add "infredients" field I reveive an error that the "food[i]" object is undefined. How can I fix this problem and return the "food" with ingredients for every elements?
Thanks

NodeJS - MySQL query error

My query works fine if the person exist in my table, but if he/she does not; the NodeJS will give me an error.
function ClientConnected(remoteClient)
{
debugLog(remoteClient.name + " connected to the server. (ID: " + remoteClient.networkId + ") Loading player data..");
sql.query('SELECT * FROM `players` WHERE `character_name` = ?', [remoteClient.name], function(err, rows)
{
if(err)
{
debugLog('[DB] Error when loading ' + remoteClient.name + "'s (" + remoteClient.networkId + ') data: ' + err.code);
} else {
players[remoteClient.networkId] = {
'a_socialid' : rows[0].account_socialid,
'i_money' : rows[0].inventory_money,
};
debugLog("Successfully loaded " + remoteClient.name + "'s (" + remoteClient.networkId + ") data..");
}
});
}
events.Add("ClientConnected", ClientConnected);
If someone joins with the name that already exists in the table, it will load the players data:
But if not, it gives me an error. (TypeError, undefined, blabla)
You need to check that a record was returned. Maybe something like this:
if(err)
{
debugLog('[DB] Error when loading ' + remoteClient.name + "'s (" + remoteClient.networkId + ') data: ' + err.code);
} else if (rows.length === 0) {
debugLog('Nothing returned from database');
} else {
// ...
}
Presumably the err result would only give you feedback on the actual query, not the data it returns.