无法在 Dialogflow Fulfillment(在线编辑器)中从 Firestore 引入数据

Cannot bring data from Firestore in Dialogflow Fulfillment (In-line Editor)

我正在使用 Dialogflow 为 Google Assistant 构建一个 Action。一切正常,除了实现我的意图。

我正在使用 内联编辑器(由 Cloud Functions for Firebase 提供支持)来实现目的。我的函数本身运行 - 因为我可以从该函数向助手发送文本。

但出于某种原因,代码执行从未进入从 Firebase Firestore 上的 Collection 获取数据的函数 - 虽然它 是否执行前后命令。

这是我的 index.js.

中的代码
'use strict';
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
let db = admin.firestore();
const {dialogflow} = require('actions-on-google');
const app = dialogflow({debug: true});

app.intent('INTENT', (conv, {ENTITY}) => {
    conv.add("Hello.");         //THIS IS DISPLAYED

    db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
        conv.add("Hey!");       //THIS IS NOT DISPLAYED
    snapshot.forEach(doc => {
        conv.add("Hi?");        //NOR IS THIS       
    });
        conv.add("Hmm...");     //NEITHER THIS
    }).catch(error => {
        conv.add('Error!');     //NOT EVEN THIS
    });

    conv.add("Bye.");           //THIS IS DISPLAYED TOO
});

exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

显然,这表明执行从未真正进入 db... 块,因此函数甚至没有抛出任何错误。

这是来自 Firebase 的日志。

Function execution started
Billing account not configured...
Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail
Request {...}
Headers {...}
Conversation {...}
Response {...}
Function execution took 1681 ms, finished with status code: 200

我知道firestore函数是异步获取数据的,但是有 似乎我无法在其 .then(...) 块内执行任何操作。

我还尝试从 .then(...) 块中 returning 一个 Promise,并使用第二个 .then(...) - 但还是没有用。

var fetch = db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
    conv.add("Hey!");                    //NOT DISPLAYED
    var responseArr = [];
    snapshot.forEach(doc => {
        conv.add("Hi?");                 //NOT DISPLAYED  
        responseArr.push(doc);  
    });
    conv.add("Hmm...");                  //NOT DISPLAYED
    return Promise.resolve(responseArr);
}).then(fetch => {
    conv.add("Here?");                   //NOT DISPLAYED
}).catch(error => {
    conv.add('Error!');                  //NOT DISPLAYED
});

最后,我也试过把firestore函数放在一个单独的function里,像这样。

function getData(){
    return db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
        snapshot.forEach(doc => {
            ...    
        });

        return data;                //Manipulated from above. 'data' can be a string.
    }).catch(error => {
           return error;
    });
}

app.intent('INTENT', (conv, {ENTITY}) => {
    conv.add("Hello.");         //THIS IS DISPLAYED

    conv.add(getData());        //THIS IS NOT DISPLAYED

    conv.add("Bye.");           //THIS IS DISPLAYED
});

问题在于您正在执行异步操作(调用 get()),但您并未 return 从 Intent Handler 本身获取 Promise。该库要求您 return 一个 Promise,以便它知道正在进行异步操作。

Return 中的 Promise then() 部分是不够的 - return 中的值不是处理程序,它只是 return 传递给下一个 then() 函数的值,或者(如果它是最后一个)作为整个 Promise 链的 return 值。

在您的原始代码中,只需 returning get().then().catch() 链即可完成此操作。你的第一行是这样的:

return db.collection("COLLECTION").orderBy("FIELD", "desc").get() // etc etc

在您的第二个示例中,then() 块中的 fetch 不是您认为的 fetch,只会混淆问题。以这种方式构建,您需要 return 来自 let 作业的 fetch

你的第三个例子比较复杂。行

conv.add(getData());

从表面上看,它甚至似乎都行不通,因为它是 return 一个 Promise,但您不能向 conv 对象添加一个 Promise。您需要将该部分重写为

return getData()
  .then( data => conv.add( data ) );

但这并没有说明 "Bye" 行的工作方式。如果你真的想要 "Bye" 在数据之后,你必须将它作为 then() 块的一部分。

简而言之,在处理异步数据时,需要

  1. 确保您了解 Promises 的工作原理并确保所有异步工作都使用 Promises 完成。
  2. 将所有数据添加到 Promisethen() 部分
  3. Return一个正确的承诺