Firebase Database Function not working as it should on DialogFlow - javascript

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

knex.raw and trx.commit in knex.transactions

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)
]);
})

CRUD data in firestore using firebase function onCall. What happens to any async operation (Promise) within it?

Nothing happens to my firestore when I call the function below. I also can't see "inside helloWorld" on my GCP logs.
exports.helloWorld = functions.https.onCall((data, context) => {
console.log("inside helloWorld);
const users = admin.firestore().collection('users');
users.doc(data.userId).get().then( // --------------------Line A
(snapshot) => {
if (snapshot.exists) {
console.log("snapshot exists");
return null;
} else {
console.log("inside else");
users.doc(data.userId).set({
name: data.name
});
return null;
}
}
).catch(() => 'obligatory catch');
return; //-----------------------------------------------Line B
});
However, when I place the return on Line A, the function works as expected and a document is created in my firestore. "inside helloWorld" is shown on my GCP logs.
Why is that so?
I really appreciate any levels of clarification.
According to the documentation for callable functions (particularly the part about sending back a result):
To return data after an asynchronous operation, return a promise. The
data returned by the promise is sent back to the client. For example,
you could return sanitized text that the callable function wrote to
the Realtime Database.
Even if you don't want to send any content in the response, Callable functions still need to respond to the HTTP request that originated them, as all HTTP transactions do.
In either case, you still need to make use of the promises in all your async calls so that Cloud Functions knows when to respond to the client, after all the work is complete. Placing the return statement on "line A" is effectively returning the promise from the async work started by get(), fulfilling this requirement. Without the return statement, Cloud Functions is terminated your function because it thinks there is no more work to complete in order to send the final response.
If you're not familiar about how promises work in JavaScript, watch my video tutorials here: https://firebase.google.com/docs/functions/video-series/

Passing a value between chained Promises in Cloud Functions for Firebase

I am implementing a Stripe payment module in a Firebase web application.
I create a Stripe charge through a Cloud Function, as follow:
exports.createStripeCharge = functions.database.ref('...').onWrite(event => {
....
let chargeStatus;
return stripe.charges.create(charge, {idempotency_key})
.then(returnedcharge => {
chargeStatus = returnedcharge.status;
return event.data.adminRef.set(returnedcharge)
})
.then(() => {
return admin.database().ref(`/stripeCardCharges/${event.params.orderId}`).set({'status': chargeStatus});
})
.catch(error => {
...
})
As you see I try to follow the advices from the Firebase team to carefully chain the promises.
However I need the returnedcharge object to be used in two promises, chained one after the other:
The first time to write the entire object to the Real Time Database
The second time because I want to write returnedcharge.status to the database, but at another node (because of different access rights)
I have then created a variable that I populate in the first promise and use later in the next one.
My question is: Is this the good approach?
Another linked question (for which I think the answer is "no"!): would it be possible (and make sense!) to combine the two database write (i.e. set) in one promise only? If yes, what do you return then?
Looks OK to me. Seems to get the job done without problems.

Callback in Node.js and Database variable [duplicate]

This question already has an answer here:
Returning a value from callback function in Node.js [duplicate]
4 answers
How do I return the response from an asynchronous call?
34 answers
I don't understand callbacks in nodejs.
I need to get a podcast number from the database and use it in my code
I get right now from console.log
[Function: index]
Is there any solution in node.js to get variable from a database and reuse it later in the code?
var index = function( callback ) {
var podcast = 0;
User.findOne({ sessionID: this.event.session.sessionId }, function(err, user) {
if (err ||!user){
}
else {
console.log(user);
podcast = user.podcast;
}
});
callback( podcast );
};
index();
var callback = function(data) {
return data;
}
var iUseMyAnywhere = callback;
It look like it is impossible what I want to do in Node.js
It's completely possible. Only, you need to use asynchronous API's, which makes it ankward.
Is there any solution in node.js to get variable from a database and reuse it later in the code?
Not exactly. When you connect to a database -or, by the way, do anything asynchronously, like fetching something over http or reading from disc- you can't assign that thing right over:
var myUserFromDb = User.find('john doe', function(err, res){...}); //this will fail
Because that function you're passing as the second parameter will execute sometime in the future. User.find() itself doesn't return the user.
So, sadly, you can't just get the user in the user var and pass it to another module -let's say a podcast module-.
However, let's say you have a 'user.js' module, with exposes a withUser method than aks the database for a user and then calls a provided function with the user, when the db call is resolved.
And let's say you have a 'podcast.js' file/module with a getPodcast method that needs a user.
getPodcast can't just ask 'user.js' a user. However, it can ask for a function that will run with the user passed as parameter:
User.js
function withUser(callback){
User.find({_id: 1}, (err, user)=> {
callback(user);
})
}
podcast.js
function getPodcast(){
withUser( function(user){
//now we really have the user inside podcast.js, and we can work with it.
//Sadly, that will surely involve more asynchronous api's, which is painful.
})
}
Now getPodcast will have access to the user inside its parameter callback.
Is there any easier method rather than callback?
Yes, you should read about promises. When using promises, things are -a little less- painful. A promise api would work as:
User.js
function getUser(id){
//let's say we return a promise that wraps the `User.find` database request
}
podcast.js
getUser(userId).then(user => getPodcast(user)).then(podcastResult => ...)
This don't see really better. However, when you are working with promise api's, you can then start using async/await.
podcast.js
async function getPodcast(userId){
const user = await User.getUser(uesrId);
const otherAsyncThing = await ...someAsyncApiCall;
doAnythingWithUser(user); //this line won't execute until user is resolved, even if there aren't callbacks involved :-D
}
A final, unasked word of advice: when working with node.js, be sure you understand how callback api's and async things really work before writing a ton of code. Otherwise, you'll get really coupled and brittled code, where objects get passed through mountains of callbacks and code is unreadable and undebuggable :-D
PS. Edited to follow question.
Think like this, you get to a restaurant, sit down and ask a waitress for a coffee. But in the meanwhile you are not frozen, you are moving, doing things, talking, so once your coffee is ready, the waitress will bring it to you and you will stop other things that you are doing and drink your coffee.
So, it would become something like this:
User.findOne({ sessionID: this.event.session.sessionId }).exec().then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});

return $add ref of Firebase item AngularFire

Let's say I have a collection of items:
var itemsRef = new Firebase("https://example.firebaseio.com/items");
$scope.items = $firebase(itemsRef);
And we $add an item:
$scope.items.$add($scope.item);
I understand the ref gets generated client side before making it to the Firebase collection.
How do I get that ref after adding the item? For example -Jx8363hdu12
AngularFire 0.6.0
As of AngularFire 0.6.0 $add, $save, $set and $remove use promises:
https://github.com/firebase/angularFire/issues/183
$scope.items.$add($scope.item).then(function(p){
console.log(p.name());
});
For others coming by here if you had code that previously worked using
var bleh = $scope.items.$add($scope.item);
Previously $add would return the actual value, but as Dan mentioned above it was changed to return a promise.
You have two options (the later being the better).
Move back to an older version of angularfire.
You will HAVE to use the .then operation.
I have had this problem a few times and keep running into it (i'm hoping the more variations on the term can be found the more likely if it happens again to me or others it'll be easier to find).
I had it in my head that a promise meant that you could still use the variable and at some point in the future it would fill it in (so I kept thinking that it would fill it in eventually and was getting annoyed that it never seemed to).
From here: http://www.html5rocks.com/en/tutorials/es6/promises/
Here's how you use that promise:
promise.then(function(result) {
console.log(result); // "Stuff worked!"
}, function(err) {
console.log(err); // Error: "It broke"
});
"then" takes two arguments, a callback for a success case, and another for the failure case. Both are optional, so you can add a callback for the success or failure case only.
So in theory if firebase errors out saving the data (adding/removing/etc) you should at least have the error function so you can trap that something wrong has happened.
For Dan's example:
$scope.items.$add($scope.item).then(
function(p){
console.log(p.name());
},
function(err){
console.log("The expected Firebase action failed to occur this was your error: " + err);
});

Resources