Unable to read from firestore collection - google-cloud-firestore

i have a firestore collection called Users and trying to write a document in the collection through fulfillment. I am getting the user's name and his location through dialogflow agent and trying to insert it into the collection. But the document is not getting inserted.
1)Getting data from agent:
name= agent.parameters.name;
location=agent.parameters.location;
2) Writing to the firestore collection Users
db.collection("Users").doc("101").set({
name: name,
location:location});
The function got executed but the document is not inserted into the firestore collection. what am i missing?
'use strict';
const functions = require('firebase-functions');
const { WebhookClient } = require('dialogflow-fulfillment');
const { Card, Suggestion } = require('dialogflow-fulfillment');
const admin = require('firebase-admin');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
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));
var name='';
var location='';
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
function getUserDetails(agent)
{
name= agent.parameters.name;
location=agent.parameters.location;
console.log("buyer name is " + name);
db.collection("Users").doc("101").set({
name: name,
location:location});
agent.add(`User has been inserted`);
}
intentMap.set('Buy Car', getUserDetails);
agent.handleRequest(intentMap);
})

'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) =>
{const agent = new WebhookClient({request,response});
function saveName(agent){
const nameParam = agent.parameters.name;
const name = nameParam;
agent.add(`thank you, ` + name + `!`);
return db.collection('test').add({name: name}).then((snapshot) => {(console.log('success'));
});
}
let intentMap = new Map();
intentMap.set('Get_Name', saveName);
agent.handleRequest(intentMap);
});

It isn't clear what is going wrong, but at least in part that is because you're not checking what the error might be from doing the write to the collection/doc.
This is compounded by your reply "User has been inserted" is sent without you actually confirming that the user document has been set. There isn't even any guarantee that it has been sent by the time the function completes, because you're not treating the document write as asynchronous.
The normal way to do this is to return the Promise that set() returns, so handleRequest() will wait for the handler to finish before it sends the reply. You should also set the reply in a then() portion of the Promise and catch any errors in a catch() block.
A function like this is more correct, and may log what the error is:
function getUserDetails(agent)
{
name= agent.parameters.name;
location=agent.parameters.location;
console.log("buyer name is " + name);
return db.collection("Users").doc("101").set({
name: name,
location: location
})
.then( () => {
agent.add(`User has been inserted`);
})
.catch( err => {
console.log( err );
agent.add('Something went wrong');
});
}

Related

How do I make 2 (or more) calls with Adobe PDF Services and skip using the file system (in between?)

It's fairly simple to make one call to Adobe PDF Services, get the result, and save it, for example:
// more stuff above
exportPdfOperation.execute(executionContext)
.then(result => result.saveAsFile(output))
But if I want to do two, or more, operations, do I need to keep saving the result to the file system and re-providing it (is that even a word ;) to the API?
So this tripped me up as well. In most demos, you'll see:
result => result.saveAsFile()
towards the end. However, the object passes to the completed promise, result, is a FileRef object that can then be used as the input to another call.
Here's a sample that takes an input Word doc and calls the API method to create a PDF. It then takes that and runs OCR on it. Both methods that wrap the API calls return FileRefs, so at the end I saveAsFile on it. (Note, this demo is using v1 of the SDK, it would work the same w/ v2.)
const PDFToolsSdk = require('#adobe/documentservices-pdftools-node-sdk');
const fs = require('fs');
//clean up previous
(async ()=> {
// hamlet.docx was too big for conversion
const input = './hamlet2.docx';
const output = './multi.pdf';
const creds = './pdftools-api-credentials.json';
if(fs.existsSync(output)) fs.unlinkSync(output);
let result = await createPDF(input, creds);
console.log('got a result');
result = await ocrPDF(result, creds);
console.log('got second result');
await result.saveAsFile(output);
})();
async function createPDF(source, creds) {
return new Promise((resolve, reject) => {
const credentials = PDFToolsSdk.Credentials
.serviceAccountCredentialsBuilder()
.fromFile(creds)
.build();
const executionContext = PDFToolsSdk.ExecutionContext.create(credentials),
createPdfOperation = PDFToolsSdk.CreatePDF.Operation.createNew();
// Set operation input from a source file
const input = PDFToolsSdk.FileRef.createFromLocalFile(source);
createPdfOperation.setInput(input);
let stream = new Stream.Writable();
stream.write = function() {
}
stream.end = function() {
console.log('end called');
resolve(stream);
}
// Execute the operation and Save the result to the specified location.
createPdfOperation.execute(executionContext)
.then(result => resolve(result))
.catch(err => {
if(err instanceof PDFToolsSdk.Error.ServiceApiError
|| err instanceof PDFToolsSdk.Error.ServiceUsageError) {
reject(err);
} else {
reject(err);
}
});
});
}
async function ocrPDF(source, creds) {
return new Promise((resolve, reject) => {
const credentials = PDFToolsSdk.Credentials
.serviceAccountCredentialsBuilder()
.fromFile(creds)
.build();
const executionContext = PDFToolsSdk.ExecutionContext.create(credentials),
ocrOperation = PDFToolsSdk.OCR.Operation.createNew();
// Set operation input from a source file.
//const input = PDFToolsSdk.FileRef.createFromStream(source);
ocrOperation.setInput(source);
let stream = new Stream.Writable();
stream.end = function() {
console.log('end called');
resolve(stream);
}
// Execute the operation and Save the result to the specified location.
ocrOperation.execute(executionContext)
.then(result => resolve(result))
.catch(err => reject(err));
});
}

Dialogflow to Firestore using Inline Fulfillment - Get original user input from a certain parameter

Is there a way to get the original input from a certain parameter?
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
process.env.DEBUG = 'dialogflow:debug';
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function getData(agent) {
let age = agent.parameters.age;
let location = agent.parameters.location;
let opinion = agent.parameters.opinion;
db.collection("users").add({
age: age,
location: location,
opinion: opinion
});
}
let intentMap = new Map();
intentMap.set('getData', getData);
agent.handleRequest(intentMap);
});
e.g. The user inputs "I love this thing!"
This is the data that was stored in Firestore.
Notice that only the word "love" was stored in the opinion line since my #opinion entity has only the word love. This is the getData intent.
This is what I'm trying to achieve.

mongo db transaction with multiple collection not working

the following function is supposed to do:
save the project into collection 'project_list'
push the uuid of the new project to a client in the collection 'client_list'
with transaction enabled, if anything goes wrong (such as the client id is given in the new project JSON object does not exist in the collection 'client_list'), then both step1 and step2 will be canceled.
noticed that the code is giving the client_id as 'invalid-uuid' to updateOne which will not add the project uuid to the client because the client_id does not exist in the collection but the new project is saved into collection 'project_list' with or without me doing commitTransaction.
I was reading this https://mongoosejs.com/docs/transactions.html which suggest me to abort the transaction by calling await session.abortTransaction(); but i dont know how to implement it.
thanks in advance.
transactionCreateProject: async function (newProjectJson) {
const mongoConnectConfig = {useNewUrlParser: true, useUnifiedTopology: true};
await mongoose.connect(CONSTANTS.ADMIN_MONGO_URL, mongoConnectConfig)
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
db.once("open", function (callback) {
console.log("Connection Succeeded")
});
let project = mongoose.model('project', mongooseProjectSchema)
let client = mongoose.model('client', mongooseClientSchema)
const session = await mongoose.startSession();
session.startTransaction();
try {
console.log(newProjectJson.clientUUID)
let newProjectMongooseObject = new project()
for (let i = 0; i < Object.keys(newProjectJson).length; i++){
// assigning the attributes of new project to mongoose object
newProjectMongooseObject[Object.keys(newProjectJson)[i]] = newProjectJson[Object.keys(newProjectJson)[i]]
}
newProjectMongooseObject['createdAt'] = dateObject.toISOString();
let saveRes = await newProjectMongooseObject.save()
let addProjectToClientRes = await clientMongooseModel.updateOne({ 'uuid': "invalid-uuid"}, {$push: {'projects': { projectID: newProjectJson.uuid}}})
}
catch (e) {
console.log(e)
return null
}
finally {
console.log("in finally, session ending")
session.endSession();
}
return null
},

Axios sending url with params as string not object

i need to take url with params example:
https://domain.pl/ptpdf-gen?selected_posts=4871&advisor=magda,wojciech
But axios response is an object like:
{"https://domain.pl/ptpdf-gen?selected_posts":"4871","advisor":"magda,wojciech"}
How to send url as string via axios?
Optionally the request above could also be done as
axios.get('/user', {
params: {
selected_posts: 4871
advisor: ["magda", "Wojciech"]
},
paramsSerializer: params => {
return qs.stringify(params)
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
The qs is an external library,
https://www.npmjs.com/package/qs
var selected = 4871
var advisor = ["magda","wojciech"]
axios.post('https://domain.pl/ptpdf-gen', {selected, advisor })
So i made the url split like this, using URLSearchParams:
const currHref = window.location.search;
const urlParams = new URLSearchParams(window.location.search);
const myParam = urlParams.get('selected_posts');
const myParam2 = urlParams.get('advisor');
Then with axios.post i can send params:
axios.post("http://domain.pl/create", {myParam, myParam2})
On server i did handle params like:
const state = req.body;
const stateValues = Object.values(state);
And then i can concat url with stateValues[0] and stateValues[1];
let linkUrl = "https://domain.pl/ptpdf-gen?selected_posts=" + stateValues[0] + "&advisor=" + stateValues[1];
Works.

Webhook call failed. Error: DEADLINE_EXCEEDED. though the request latency took 4991ms

here's my fulfillment code in the inline editor :
NOTE: requests are reaching my api server with 200 OK code but says deadline exceeded in the dialogflow platform. I hope you find with me a solution the faster you can`
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');`
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
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));
let number = request.body.queryResult.parameters['number'];
var url = 'https://7400546e4d1e.ngrok.io/api/reclamations'+'/'+ number ;
getDescription(url).then(response => {
var bot_response = "description:"+response.data.description ;
agent.add(bot_response);
console.log(bot_response);
response.json({ 'fulfillmentText': bot_response });
}).catch (error => {
console.log("Something is wrong !! ");
console.log(error);
agent.add(bot_response);
});
function getDescription(url) {
const axios = require('axios');
return axios.get(url,{timeout:10000});
}
});
Try defining the function getDescription as an async function (ie. async function getDescription(url){...}).
This is because when you call getDescription(url).then(response => {...}), the .then() implies that it is asynchronous, which it is.