I'm writing a code for a chatbot and i'm having a problem with the database query on my firebase DB that I don't know how to fix, because it is the same as the other examples I found.
var ref = admin.database().ref();
var consultasRef = ref.child('consultas')
agent.add('Test 2')
consultasRef.on("value", function(snap){
agent.add('Test 3')
agent.add(snap.val());
});
As said the function that should print the snap.(val). It's not starting as it should. The right syntax is the same as the one I use. "Test 2" is being printed, unlike "Test 3", which is inside the function
For those unfamiliar with Dialogflow, agent.add() is the same as console.log() on JS, but for Dialogflow.
When you make an asynchronous call (such as a database call), you must return a Promise from your Intent Handler so it knows when the call has completed so it can send the result back to the bot.
Additionally, you probably want to use the once() function, since you don't care about the database updating (since the result will already have been sent).
You can probably do both of these with code looking something like this:
return consultasRef.once('value')
.then( snap => {
agent.add('Test 3');
agent.add(snap.val());
});
There may also be issues with adding more than one or two text replies, depending on the Integration you're using.
Related
I'm creating a web app with Vue.js (this is the first time I use it). The app is basically a multi user real time quiz, in which every user have to choose a role and to answer questions related with his role. I use a collection in cloud firestore database to store questions associated to each role and answers associated to each question. Moreover each answer is characterized by a field "nextQuestion" that contains the id of the next question to visualize, a field "nextUser" that contains the id of the next user at which this new question is related (these fields are used in queries to select the next question and its possible answers) and a boolean field "default" that indicates, if true, the answer that is chosen in the case user don't answer the question within the set time (others to a field indicating the text of the answer). I get questions and answers with a query to visualize them on the webapp.
My problem is related to the situation in which the user doesn't answer a question within the set time (meanwhile if a user selects an answer within the set time, I haven't problems). When the time for an answer expires, I call this function:
CountTerminated: function () {
if(this.optionSelected == false){ //optionSelected is a component variable that informs if a user has selected or not an answer
this.onNotSelectedAnswer(this.getDefaultAnswer())
}
else{
this.onClickButtonConfirm() //function called if the user selects an answer within the set time
}
}
The function getDefaultAnswer() gets the fields (among which "nextUser" and "nextQuestion") of the default answer associated with the current question (through a query) and return them through a variable:
getDefaultAnswer(){
var data
db.collection("Utenti").doc(this.userId).collection("Domande").doc(this.questionId).collection("Risposte").where("default","==",true).get().then(querySnapshot =>{
querySnapshot.forEach(doc=>{
data = doc.data()
})
})
return data
},
the function onNotSelectedAnswer(data) mainly takes in input the value returned by getDefaultAnswer(), it assigns "data" to the component variable answerId and it updates the value of the component variable "userId" (that informs about the role of the user who have to answer the current question),the value of the component variable "questionId" (that contains the id of the current question) and the value of questionValue(that contains the text of the current question) using functions setUserId(), setQuestionId(), setQuestionValue()
onNotSelectedAnswer: function(data){
if(this.userChoice == this.userId){
this.answerId = data
this.setUserId(this.answerId.nextUser)
this.setQuestionId(this.answerId.nextQuestion)
this.setQuestionValue()
this.optionSelected = false
this.answers=[]
this.isActive = ""
this.getAnswers() //function used to query (using updated values of userId and questionId variable) the DB to obtain a question and its related possible answers
var a = this.channel.trigger('client-confirmEvent',{ user: this.userId, question : this.questionId, questionval: this.questionValue})
console.log(a)
}
}
The problem is related to the fact that in onNotSelectedAnswer() function, answerId is "undefined" instead of containing the result of the query and therefore the data that I will use to upload the new question. I don't understand which is the error, I hope that you can help me.
The problem is that the Firestore query is asynchronous but you aren't waiting for the response before continuing. Effectively what you have is this:
getDefaultAnswer () {
var data
// This next bit is asynchronous
db.doLotsOfStuff().then(querySnapshot => {
// This callback won't have been called by the time the outer function returns
querySnapshot.forEach(doc => {
data = doc.data()
})
})
return data
},
The asynchronous call to Firestore will proceed in the background. Meanwhile the rest of the code in getDefaultAnswer will continue to run synchronously.
So at the point the code reaches return data none of the code inside the then callback will have run. You can confirm that by putting in some console logging so you can see what order the code runs in.
The use of then to work with asynchronous code is a feature of Promises. If you aren't already familiar with Promises then you should study them in detail before going any further. Here is one of the many guides available:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
The bottom line is that you cannot force the getDefaultAnswer method to wait for the asynchronous action to complete. What you can do instead is to return a suitable Promise and then wait for that Promise to resolve before you call onNotSelectedAnswer. It might look something like this:
getDefaultAnswer () {
// We return the Promise chain from getDefaultAnswer
return db.doLotsOfStuff().then(querySnapshot => {
var data = null
// I have assumed that forEach is synchronous
querySnapshot.forEach(doc => {
data = doc.data()
})
// This resolves the Promise to the value of data
return data
})
},
It is important to appreciate that the method getDefaultAnswer is not attempting to return the value of the data. It is instead returning a Promise that will resolve to the value of the data.
Within CountTerminated you would then use it like this:
this.getDefaultAnswer().then(defaultAnswer => {
this.onNotSelectedAnswer(defaultAnswer)
})
or if you prefer:
this.getDefaultAnswer().then(this.onNotSelectedAnswer)
The latter is more concise but not necessarily clearer.
You could also write it using async/await but I wouldn't advise trying to use async/await until you have a solid grasp of how Promises work. While async/await can be very useful for tidying up code it is just a thin wrapper around Promises and you need to understand the Promises to debug any problems.
The code I've suggested above should work but there is a delay while it waits for the asynchronous request to complete. In that delay things can happen, such as the user may click on a button. That could get you into further problems.
An alternative would be to load the default answer much sooner. Don't wait until you actually need it. Perhaps load it as soon as the question is shown instead. Save the result somewhere accessible, maybe in a suitable data property, so that it is available as soon as you need it.
Im just new to knex and came across Transactions. I think it's useful to use since it has a rollback feature. Tried using it (see code below)
await knex.transaction(trx => {
knex.raw(delete from myTable where "id" = 1 )
.transacting(trx)
.then(trx.commit)
.catch(trx.rollback)
})
I just wanted to delete a row with a certain id nothing more and less.
Works fine, then i tried to remove 'trx.commit'. I was expecting that it wont apply the query but it did. From what I understand, if trx.commit is not called the query will not run and wont affect the database.
Is my understanding wrong? Did I use knex.raw improperly inside knex.transactions? I dont see examples of transactions that uses raw queries. I am connected to a database in my localhost(postgresql) btw.
knex.js has a modified promise interface.
Calling .then triggers the query to actually fire (including the BEGIN transaction if it is the first query). Note that in a single knex query you won't need to call rollback since a single query to the database should be transactional and abort/rollback if any errors are encountered.
Based on your usage (and the docs) if you remove trx.commit it should not commit at all. I recommend actually returning a promise to the transaction callback - then it will auto-commit on promise resolution, and auto-rollback on promise failure.
In the following usage if either query failed it would auto-rollback everything.
knex.transaction(trx => {
return Promise.all([
knex.raw(`update table x`).transacting(trx),
knex.raw(`update table y`).transacting(trx)
]);
})
I'm running into problems with the validated method package in my app tests. I'm calling my methods through the _execute function in order to be able to pass a userId to simulate a logged-in user while testing. The problem is that my asserts right underneath that _execute are called before the method has a chance of completing. I know my test works though because it only happens sometimes, mostly because mongo isn't always returning results quite as fast.
I looked around and found a todos app that uses the _execute function in its tests. I can't get those tests to fail no matter how many times I rerun them, though.
This is an example of my test code.
describe('clients.add', function() {
it('should add an empty (draft) client', function() {
const res = clients_add._execute({ userId: 'CURRENTUSERID' }, { company_id: c1._id });
assert.instanceOf(res, Mongo.ObjectID, 'method returns the newly created clients ID');
const db_client = Clients.findOne(res);
assert.isTrue(db_client.draft, 'client is drafted');
assert.isDefined(db_client.created, 'there\'s a created date');
});
});
clients_add does quite a few permission checks and can therefor take a little while before completing. Rerunning this test 20 times will fail about 5 times and pass the other 15.
Shouldn't the _execute function be synchronous? How do I make it? What am I missing?
In server code, if you provide a callback to database modification functions like insert, it returns the created ID instantaneously, and runs the callback only once the database has acknowledged the write. If you don't provide a callback, the insert call is synchronous and throws an error if the operation fails. See more about this in Meteor docs.
It seems that you have provided an error-handling callback to the insert-function in your method code. This causes the inconsistent behavior, since the database might not actually have had time to do the write before you call findOne in your test. Also, this is redundant since if an error occurs in the insert, the method has already returned and the error is never shown to the user. It's better to simply omit the error-handling callback altogether:
return Clients.insert(new_client);
if I have a code like this
if (request.params.friends != null)
{
_.each(request.params.friends, function(friend) {
// create news
var News = Parse.Object.extend("News");
var news = new News();
news.set("type", "ask");
news.save();
});
response.success();
}
and the length of request.params.friends is 2, does the second news get saved for certain? If not, how to make sure it gets saved? I looked at Parse.Promise documentation and in all the examples, the loop is inside a query or a save. Do I need to save the first news first and then create the Promise? I still don't get how "asynchronous" works.. Does the response.success() work like a return or break?
The loop does get executed twice.
response.success() acts like a return.
The asynchronous magic is in the "save" method. When "save" is called, the Parse.com says, "ok, you want me to save it. I'll save it, but not now. For now, here is a promise that I'll save it later." The save method returns an Promise object and the promise will be fulfilled when the object is actually saved.
So what happens is a little like
First time through the loop: create friend #1.
Ask Parse to save friend #1.
Second time through the loop: create friend #2.
Ask Parse to save friend #2.
Return successful response.
Parse actually saves friend #1 and friend #2
It's been a while since I've used Parse, but I'm not sure usually both the friend objects would actually get saves. Calling response.success() could kill work-in-progress. Here is an alternative implementation:
var objectsToSave = _.collect(request.params.friends, function(friend) {
var news = new News();
news.set({type : "ask"});
return news;
});
Parse.Object.saveAll(objectsToSave, {
success: function(list) {
// All the objects were saved.
response.success();
},
error: function(error) {
// An error occurred while saving one of the objects.
},
});
The saveAll function saves all the objects at once. It's usually faster than saving objects one-at-a-time. In addition to providing saveAll with the objects to save, we provide it an object with a success function and an error function. Parse.com promises only to call the functions AFTER the save is complete (or it experienced an error).
There are a few other things going on. The Parse.Object.extend statement belongs in a different place in your code. Also, the set function doesn't take a list of strings. It takes a JavaScript object.
Is there a way to wait on a promise so that you can get the actual result from it and return that instead of returning the promise itself? I'm thinking of something similar to how the C# await keyword works with Tasks.
Here is an example of why I'd like to have a method like canAccess() that returns true or false instead of a promise so that it can be used in an if statement. The method canAccess() would make an AJAX call using $http or $resource and then somehow wait for the promise to get resolved.
The would look something like this:
$scope.canAccess = function(page) {
var resource = $resource('/api/access/:page');
var result = resource.get({page: page});
// how to await this and not return the promise but the real value
return result.canAccess;
}
Is there anyway to do this?
In general that's a bad idea. Let me tell you why. JavaScript in a browser is basically a single threaded beast. Come to think of it, it's single threaded in Node.js too. So anything you do to not "return" at the point you start waiting for the remote request to succeed or fail will likely involve some sort of looping to delay execution of the code after the request. Something like this:
var semaphore = false;
var superImportantInfo = null;
// Make a remote request.
$http.get('some wonderful URL for a service').then(function (results) {
superImportantInfo = results;
semaphore = true;
});
while (!semaphore) {
// We're just waiting.
}
// Code we're trying to avoid running until we know the results of the URL call.
console.log('The thing I want for lunch is... " + superImportantInfo);
But if you try that in a browser and the call takes a long time, the browser will think your JavaScript code is stuck in a loop and pop up a message in the user's face giving the user the chance to stop your code. JavaScript therefore structures it like so:
// Make a remote request.
$http.get('some wonderful URL for a service').then(function (results) {
// Code we're trying to avoid running until we know the results of the URL call.
console.log('The thing I want for lunch is... " + results);
});
// Continue on with other code which does not need the super important info or
// simply end our JavaScript altogether. The code inside the callback will be
// executed later.
The idea being that the code in the callback will be triggered by an event whenever the service call returns. Because event driven is how JavaScript likes it. Timers in JavaScript are events, user actions are events, HTTP/HTTPS calls to send and receive data generate events too. And you're expected to structure your code to respond to those events when they come.
Can you not structure your code such that it thinks canAccess is false until such time as the remote service call returns and it maybe finds out that it really is true after all? I do that all the time in AngularJS code where I don't know what the ultimate set of permissions I should show to the user is because I haven't received them yet or I haven't received all of the data to display in the page at first. I have defaults which show until the real data comes back and then the page adjusts to its new form based on the new data. The two way binding of AngularJS makes that really quite easy.
Use a .get() callback function to ensure you get a resolved resource.
Helpful links:
Official docs
How to add call back for $resource methods in AngularJS
You can't - there aren't any features in angular, Q (promises) or javascript (at this point in time) that let do that.
You will when ES7 happens (with await).
You can if you use another framework or a transpiler (as suggested in the article linked - Traceur transpiler or Spawn).
You can if you roll your own implementation!
My approach was create a function with OLD javascript objects as follows:
var globalRequestSync = function (pUrl, pVerbo, pCallBack) {
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function () {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
pCallBack(httpRequest.responseText);
}
}
httpRequest.open(pVerbo, pUrl, false);
httpRequest.send(null);
};
I recently had this problem and made a utility called 'syncPromises'. This basically works by sending what I called an "instruction list", which would be array of functions to be called in order. You'll need to call the first then() to kick things of, dynamically attach a new .then() when the response comes back with the next item in the instruction list so you'll need to keep track of the index.
// instructionList is array.
function syncPromises (instructionList) {
var i = 0,
defer = $q.defer();
function next(i) {
// Each function in the instructionList needs to return a promise
instructionList[i].then(function () {
var test = instructionList[i++];
if(test) {
next(i);
}
});
}
next(i);
return defer.promise;
}
This I found gave us the most flexibility.
You can automatically push operations etc to build an instruction list and you're also able to append as many .then() responses handlers in the callee function. You can also chain multiple syncPromises functions that will all happen in order.