Reputation: 554
I wrote a basic function that connects to MongoDB using Mongoose, and reads documents. I deployed the code in Cloud Functions. It responded correctly with the documents from MongoDB.
var mongoose = require('mongoose');
var mongoDB = "mongodb://IP:port/db";
mongoose.connect(mongoDB, {
useNewUrlParser: true
});
var db = mongoose.connection;
var Schema = mongoose.Schema;
var myCollection = new Schema({name: String,PO: String},{collections: 'myCollection'});
var myCollectionModel = mongoose.model('myCollection', myCollection, 'myCollection');
exports.helloWorld = (req, res) => {
db.on('error', console.error.bind(console, 'connection error:'));
myCollectionModel.find({name : "Jeeva"}, function(error, PO) {
res.send(PO[0]);
});
};
I wrote the code to accommodate in Dialogflow fulfillment in the following directions: When the intent is called, fetch the data, return it to the user.
'use strict';
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
var mongoose = require('mongoose');
var mongoDB = "mongodb://IP:Port/db";
mongoose.connect(mongoDB, {useNewUrlParser: true});
var db = mongoose.connection;
var db = mongoose.connection;
var Schema = mongoose.Schema;
var myCollection = new Schema({name: String,PO: String},{collections: 'myCollection'});
var myCollectionModel = mongoose.model('myCollection', myCollection, 'myCollection');
process.env.DEBUG = 'dialogflow:debug';
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function getData(name){
var PO_number;
myCollectionModel.find({name : "Jeeva"}, function(error, PO) {
PO_number = PO[0].PO;
});
return PO_number;
}
function pending(agent){
var name = agent.parameters.person;
try{
var PO_number = getData(name);
agent.add(PO_number);
}catch(error){
agent.add(error.toString()); // Error: Unknown response type: "undefined"
}
}
let intentMap = new Map();
intentMap.set('pending-PO',pending);
agent.handleRequest(intentMap);
});
It is not working. I tried to see the flow of code by using agent.add("here") one line at the time. I observed that the function myCollectionModel.find
which fetches the data was not getting executed.
Does Dialogflow fulfillment not support Mongoose? Does it only support Firestore? The Google project I am working on already uses Cloud Datastore so I can't create Firebase Database. If MongoDB does not work, is there any other NoSQL database that Dialogflow Fulfillment supports?
Log for Dialogflow fulfillment:
{
insertId: "xxx"
labels: {
execution_id: "xxx"
}
logName: "projects/project-name/logs/cloudfunctions.googleapis.com%2Fcloud-functions"
receiveTimestamp: "2019-08-22T10:24:25.605279456Z"
resource: {
labels: {
function_name: "dialogflowFirebaseFulfillment"
project_id: "project_id"
region: "us-central1"
}
type: "cloud_function"
}
severity: "DEBUG"
textPayload: "Function execution took 55 ms, finished with status code: 200"
timestamp: "2019-08-22T10:24:19.593202695Z"
trace: "projects/project_id/traces/xxx"
}
Upvotes: 1
Views: 434
Reputation: 50701
There are two issues with what you're doing, but you can work or around both.
First, Dialogflow fulfillment supports whatever your fulfillment platform supports. If you're using the built-in Fulfillment editor, this runs on top of Cloud Functions for Firebase. Your first issue is that, using the default pricing plan, you can only access other Google resources. You can upgrade to the "Blaze Plan", which includes a free tier which is sufficient for most development and testing.
Once you are past that, however, there is still a problem with your code structure. The myCollectionModel.find()
function runs asynchronously, which you handle by passing a callback function to it. This callback function only gets called when it gets data - but by then, the getData()
function has returned with an undefined value.
Furthermore, the Dialogflow library requires you to use JavaScript Promises if you're doing any asynchronous operation, so it knows not to send the response back before all the Promises have been resolved.
I haven't tested it, but I think you might be able to rewrite your code to be something like this:
function getData(name){
var PO_number;
return myCollectionModel.find({name : "Jeeva"}).exec()
.then( doc => {
return Promise.resolve(doc[0].PO);
})
}
function pending(agent){
var name = agent.parameters.person;
return getData(name)
.then( PO_number => {
agent.add( PO_number );
})
.catch( error => {
agent.add(error.toString()); // Error: Unknown response type: "undefined"
});
}
Upvotes: 2