Friends, I've been banging my head against my desk. I'm writing an Alexa+Lambda+Dynamodb string of actions/events. The issue comes in my Lambda Node.JS. I have the function getChores in which I'm trying to run a simple getItem() to pull just a sample entry in a dynamodb, however I can ONLY access the data returned in the Else statement but I need to pass it via the callback in speechOutput. Any assistance you can provide would be greatly appreciated!
function getChores(callback) {
sessionAttributes = {};
var params = {
TableName: 'Chores',
Key: {
'chore': {
S: 'Clean up toys'
},
}
};
// Call DynamoDB to read the item from the table
var results = ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
} else {
//CAN ONLY ACCESS HERE!
console.log("Success", data.Item);
speechOutput = data.Item.chore.S;
console.log(data.Item.chore.S);
console.log(speechOutput);
}
});
console.log(results);
//Get card title from data
const cardTitle = "Chore"
//Get output from data
//const speechOutput = element.chore;
// If the user either does not reply to the welcome message or says something that is not
// understood, they will be prompted again with this text.
const repromptText = '';
const shouldEndSession = false;
callback(sessionAttributes,
buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
}
It looks like ddb.getItem is an async method. You need to call the callback method 'callback' inside the else block.
Related
I'm trying to scrape a website with Puppeteer. I want to select the date of the last post inserted in my database and compare it to the dates taken by the scrape so I can see if the post is already in the database (using the date as the reference to see if it has been modified).
Here is my code:
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'db_webcrawler_coches'
});
connection.connect((err) => {
if (err) throw err;
console.log('Connected!');
});
let lastpublishedDate;
let idCoches;
connection.query("SELECT id_coches, publish_date FROM coches ORDER BY publish_date DESC limit 1", function (err, row) {
if (err) throw err;
lastPublishedDate = row[0].publish_date;
idCoches = row[0].id_cochesNet;
console.log("Published in", lastPublishedDate);
console.log("Id Coches", idCoches);
});
const run = async () => {
try {
const options = {
headless: false,
};
...
const news = await page.evaluate(() => {
const idsList = [...document.querySelectorAll('div.mt-SerpList-item')].map(elem => elem.getAttribute("id")).filter(elem => elem.includes("#"))
const datePost = [...document.querySelectorAll('span.mt-CardAd-date')].map(elem => elem.innerText);
for(let i = 0; i < titlesCar.length; i++){
const finalDate = parsedDates[i];
if (finalDate > lastPublishedDate || idCoches !== idsList[i]){
console.log("Not repeated");
const carsList[i] = [
idsList[i],
parsedDates[i]
]
} else {
console.log("Repeated")
}
}
return carsList;
});
...
} catch (err) {
console.log(err);
await browser.close();
console.log("Browser Closed");
}
};
run();
As you can see I want to see if the date is the same or not as well as the id taken from the query. However, it appears an error that says Evaluation failed: ReferenceError: variable "lastPublishedDate" is not defined and I imagine that it will be the same with "idCoches". I wrote some console.logs to see when it crashes and it seems that it happens when reaches the function "news".
I'm not sure if it is because it is the scope or because of the function. What do you think I should do to make it work?
Could it be the scope?
Thank you!
EDIT: SOLVED!
I post it in the case that anyone faces a similar issue.
Indeed it was the scope, it is a problem related to Puppeteer. It seems that the function with page.evaluate() is unable to take any variable outside of it. To change it you need to add the page.evaluate in the following way:
await page.evaluate((variable_1, variable_2) => { /* ... */ }, variable_1, variable_2);
The callback to your Query probably does has not returned yet when the async function is run, so whatever your trying to reference is not defined.
I'm not sure if your mysql client supports promises, but if it does you could do something like this:
const run = async () => {
const row = await connection.query("SELECT id_coches, publish_date FROM coches ORDER BY publish_date DESC limit 1")
lastPublishedDate = row[0].publish_date;
idCoches = row[0].id_cochesNet;
...
}
If that does not work you could also run everything inside the callback of the query. Hope that helps.
I am creating routers using koa. We have declared two routers as shown below.
app.get('/order/:id', async ctx => {
const { id } = ctx.params;
try {
const data = await order.findOne({
where: { order_id: id }
});
ctx.body = data;
} catch (e) {
ctx.body = e.message;
}
});
app.get('/order/customer', async ctx => {
const { id } = ctx.request.user;
try {
const data = await order.findOne({
where: { customer_id: id }
});
ctx.body = data;
} catch (e) {
ctx.body = e.message;
}
});
The first is a query that selects an order by order_id, and the second is a query that selects the order of the user with an id authenticated by the middleware.
curl http://localhost:3000/order/1
The order_id is 1 when I type in the above.
curl http://localhost:3000/order/customer
However, unlike my intention, when I enter the above, and check the query, the order_id is called customer. Is there any way I can make url simple to make /order/customer available?
If you have any questions I'm missing from the question or if you can help me, please comment or reply.
You're having the issue with order of routes definitions. You should have specific path route first and dynamic route later. Here, dynamic route I meant for /:id:
'/order/customer' // first
'/order/:id' // later
I tried sending a specific message to a client device using node js and firebase functions. But when I tried executing the function, it came back with an error saying:
Error. Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array.
The image is shown below.
I was guessing it's from my JS code. So I am posting that too. What I am actually do is retrieving a data from a specific node to be used when a totally different node is being written. So I am gonna post the JS code before the database screenshots.
exports.sendNotification8 = functions.database.ref('/Users/{user_id}/Notifications/')
.onWrite(( change,context) =>{
var user_id = context.params.user_id;
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var device_token = admin.database().ref('/Users/{user_id}/device_token').once('value');
return device_token.then(result => {
var token_id = result.val();
var str = eventSnapshot.from + " : " + eventSnapshot.message;
console.log(eventSnapshot.from);
var payload = {
data: {
name: str,
title: eventSnapshot.from,
click_action: "Chats"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToDevice(token_id, payload).then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
And below is my database screenshots...
So that's how I am retrieving the device_token node. From the user that had the newest data written to his/her notifications node. Please help. What am I doing wrong?
Wow. This has been torture. But it finally worked. I got something like this.
exports.sendNotification8 = functions.database.ref('/Users/{user_id}/Notifications/{notifications_id}')
.onWrite((change,context) =>{
var user_id = context.params.user_id;
console.log(user_id);
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = change.after.val();
var device_token = admin.database().ref('/Users/'+user_id+'/device_token').once('value');
return device_token.then(result => {
var token_id = result.val();
console.log(token_id);
var str = eventSnapshot.message;
console.log(eventSnapshot.from);
var payload = {
data: {
name: str,
title: eventSnapshot.from,
click_action: "Chats"
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToDevice(token_id, payload).then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
return;
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
I need to convert some JSON to XML with this library, I need to do that in order to send some data to the Database in a post request I am working on.
This is what req.body returns
{ DealerName: 'amrcl',
CardId: '123',
Nickname: 'mkm123',
Picture: 'http://lorempixel.com/150/150/',
Active: '1',
LegalId: '1',
TypeId: '1'
}
is dynamic data. Let me show you the code
export default function (req, res) {
try {
const connection = new sql.Connection(spConfig, function spConnection (errSpConnection) {
const request = connection.request();
if (errSpConnection) {
res.status(401);
}
request.input('Dealer_Param', sql.VarChar(1000), req.body);
request.input('param_IS_DEBUG', sql.Bit, null);
request.output('output_IS_SUCCESSFUL', sql.Bit);
request.output('output_STATUS', sql.VarChar(500));
request.execute('[mydbo].[StoredProcedure]', function spExecution (errSpExecution, dataset) {
connection.close();
if (errSpExecution) {
res.status(401);
} else {
if (request.parameters.output_IS_SUCCESSFUL.value) {
res.status(200).json({
success : 'New dealer successfully inserted.',
});
}
}
});
});
}
}
that is for Stored Procedure method which is with the mssql module.
As you see the code above, there is a failure error, because in request.input('Dealer_Param', sql.VarChar(1000), req.body); I am sending the JSON I paste at the beginning of the question. But if instead of req.body I put this XML with Dummy data '<Dealers><Detail DealerName = "TESTING123" CardId = "1222" NickName = "tester123" Active = "1" LegalId = "16545" TypeId = "1"></Detail></Dealers>' then everything works fine because the DB need to receive an XML.
So, what are your recommendations, what should I do to put the JSON data as a XML ?
I would just load the json2xml library...
install $ npm install json2xml
import the module in your code: var json2xml = require("json2xml");
and then convert the json to xml like so:
var key,
attrs=[];
for (key in req.body) {
if (req.body.hasOwnProperty(key)) {
var obj = {};
obj.key = req.body.key;
attrs.push(obj);
}
}
var dealerXml = json2xml({dealer:req.body, attr:attrs}, { attributes_key:'attr'});
request.input('Dealer_Param', sql.VarChar(1000), dealerXml);
I use NodeJS to insert documents in MongoDB. Using collection.insert I can insert a document into database like in this code:
// ...
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId; // = ???
});
// ...
How can I get the _id of inserted object?
Is there any way to get the _id without getting latest object inserted _id?
Supposing that in same time a lot of people access the database, I can't be sure that the latest id is the id of object inserted.
A shorter way than using second parameter for the callback of collection.insert would be using objectToInsert._id that returns the _id (inside of the callback function, supposing it was a successful operation).
The Mongo driver for NodeJS appends the _id field to the original object reference, so it's easy to get the inserted id using the original object:
collection.insert(objectToInsert, function(err){
if (err) return;
// Object inserted successfully.
var objectId = objectToInsert._id; // this will return the id of object inserted
});
There is a second parameter for the callback for collection.insert that will return the doc or docs inserted, which should have _ids.
Try:
collection.insert(objectToInsert, function(err,docsInserted){
console.log(docsInserted);
});
and check the console to see what I mean.
As ktretyak said, to get inserted document's ID best way is to use insertedId property on result object. In my case result._id didn't work so I had to use following:
db.collection("collection-name")
.insertOne(document)
.then(result => {
console.log(result.insertedId);
})
.catch(err => {
// handle error
});
It's the same thing if you use callbacks.
I actually did a console.log() for the second parameter in the callback function for insert. There is actually a lot of information returned apart from the inserted object itself. So the code below explains how you can access it's id.
collection.insert(objToInsert, function (err, result){
if(err)console.log(err);
else {
console.log(result["ops"][0]["_id"]);
// The above statement will output the id of the
// inserted object
}
});
if you want to take "_id" use simpley
result.insertedId.toString()
// toString will convert from hex
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
collection.save(function(err,room){
var newRoomId = room._id;
});
You could use async functions to get _id field automatically without manipulating data object:
async function save() {
const data = {
name: "John"
}
await db.collection('users').insertOne(data)
return data
}
Returns (data object):
{
_id: '5dbff150b407cc129ab571ca',
name: 'John',
}
Now you can use insertOne method and in promise's result.insertedId
#JSideris, sample code for getting insertedId.
db.collection(COLLECTION).insertOne(data, (err, result) => {
if (err)
return err;
else
return result.insertedId;
});
Similar to other responses, you can grab the variable using async await, es6+ features.
const insertData = async (data) => {
const { ops } = await db.collection('collection').insertOne(data)
console.log(ops[0]._id)
}
Another way to do it in async function :
const express = require('express')
const path = require('path')
const db = require(path.join(__dirname, '../database/config')).db;
const router = express.Router()
// Create.R.U.D
router.post('/new-order', async function (req, res, next) {
// security check
if (Object.keys(req.body).length === 0) {
res.status(404).send({
msg: "Error",
code: 404
});
return;
}
try {
// operations
let orderNumber = await db.collection('orders').countDocuments()
let number = orderNumber + 1
let order = {
number: number,
customer: req.body.customer,
products: req.body.products,
totalProducts: req.body.totalProducts,
totalCost: req.body.totalCost,
type: req.body.type,
time: req.body.time,
date: req.body.date,
timeStamp: Date.now(),
}
if (req.body.direction) {
order.direction = req.body.direction
}
if (req.body.specialRequests) {
order.specialRequests = req.body.specialRequests
}
// Here newOrder will store some informations in result of this process.
// You can find the inserted id and some informations there too.
let newOrder = await db.collection('orders').insertOne({...order})
if (newOrder) {
// MARK: Server response
res.status(201).send({
msg: `Order N°${number} created : id[${newOrder.insertedId}]`,
code: 201
});
} else {
// MARK: Server response
res.status(404).send({
msg: `Order N°${number} not created`,
code: 404
});
}
} catch (e) {
print(e)
return
}
})
// C.Read.U.D
// C.R.Update.D
// C.R.U.Delete
module.exports = router;