如何从Firebase Firestore set()调用中返回承诺? [英] How to return a promise from a Firebase Firestore set() call?

查看:43
本文介绍了如何从Firebase Firestore set()调用中返回承诺?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的问题 https://stackoverflow.com/questions/54100270/google-translate-api-and-firebase-firestore-are-killing-each-other 的跟进.道格·史蒂文森(Doug Stevenson)说,我需要返回我的函数.我们观看了他的视频了解JavaScript承诺(第3部分)以了解在Cloud Functions中进行顺序和并行工作数百次了...

This is a followup to my question https://stackoverflow.com/questions/54100270/google-translate-api-and-firebase-firestore-are-killing-each-other. Doug Stevenson said that I needed to return my functions. We watched his video Learn JavaScript Promises (Pt. 3) for sequential and parallel work in Cloud Functions a few hundred times...

我正在使用两个功能.第一个是对Google翻译的调用,现在返回翻译.第二个函数是Firestore set()调用,用于将翻译内容写入数据库.如果我不进行Google Translate调用,则 set()可以工作,但是它们一起崩溃了.具体来说,如果我调用 Firebase set()而不是Google Translate函数执行,我们将看到 Result1 ,此后再也没有.换句话说,调用数据库会停止将代码推送到 translationArray 中的代码.

I'm working with two functions. The first, a call to Google Translate, now returns a translation. The second function is a Firestore set() call, to write the translation to the database. The set() works if I don't do the Google Translate call, but together they crash. Specifically, if I call Firebase set() than the Google Translate function executes, we see Result1, and nothing further. In other words, calling the database stops to code from pushing a translation into the translationArray.

这是我的代码:

exports.Google_EStranslateEN = functions.firestore.document('Users/{userID}/Spanish/Translation_Request_NOT').onUpdate((change, context) => {
    if (change.after.data().word != undefined) {
        const { Translate } = require('@google-cloud/translate');

        // Your Google Cloud Platform project ID
        const projectId = 'myProject-cd99d';

        // Instantiates a client
        const translate = new Translate({
            projectId: projectId,
        });

        // The text to translate
        const text = change.after.data().word;
        console.log(text);
        // The target language
        const target = 'en';

        let translationArray = []; // clear translation array

        const finalPromise = translate.translate(text, target)
            .then(function (results) {
                console.log("Result1: " + results);
                console.log(Array.isArray(results));
                console.log(results[0]);
                let translation = results[0];
                console.log(translation);
                return translation
            })
            .then(function (results) {
                console.log("Translation: " + results);
                translationArray.push(results);
                return translationArray
            })
            .then(function (results) {
                console.log("TranslationArray: " + translationArray);
                console.log("Result2: " + results);
                console.log("Text: " + text)
                return admin.firestore().collection('Dictionaries').doc('Spanish').collection('Words').doc(text).collection('Translations').doc('English').set({
                    translationArray: results,
                    language: 'en',
                    longLanguage: 'English'
                });
            })
            .then(function (results) {
                console.log("Result3: " + results)
                console.log("Write succeeded!");
            })
            .catch(function (error) {
                console.error(error);
            });
    } // close if
    return 0;
}); // close oxfordPronunciationUS

Firestore set()调用不会返回任何内容,并且会终止Google Translation调用.具体来说,如果没有Firestore调用,代码将一直执行,并记录所有内容.通过Firestore调用,两个函数都不会执行(永远不会调用Google翻译),并且在文本"之后不会记录任何内容.

The Firestore set() call returns nothing, and it kills the Google Translation call. Specifically, without the Firestore call the code executes all the way through, logging everything. With the Firestore call, neither function executes (Google Translate is never called) and nothing logs after "text."

我不明白 const finalPromise 的作用.看起来像一个未使用的常量.

I don't understand what const finalPromise does. It looks like an unused constant.

我们阅读了为什么Firebase API是异步的吗?并尝试了以下代码:

We read Why are the Firebase API asynchronous? and tried this code:

var promise = admin.firestore().collection('Dictionaries').doc('Spanish').collection('Words').doc(text).collection('Translations').doc('English').set({
    translationArray: translationArray,
    language: 'en',
    longLanguage: 'English'
});
promise.then(...)

那没有帮助.

我尝试切换到IBM Watson Translate,并且发生了同样的事情.如果没有数据库调用,转换功能将完美运行.通过Firestore调用,它将获取翻译,运行 forEach ,然后在我尝试将单词推入数组时停止. translationsArray 不会记录日志,也不会写入数据库.

I tried switching to IBM Watson Translate, and the same thing is happening. Without the database call the translation function works perfectly. With the Firestore call it gets the translation, runs the forEach, and then stops when I try to push the word into the array. translationsArray doesn't log and nothing writes to the database.

exports.IBM_EStranslateEN = functions.firestore.document('Users/{userID}/Spanish/Translation_Request_IBM').onUpdate((change, context) => {
    if (change.after.data().word != undefined) {

        let word = change.after.data().word;
        let wordArray = [];
        wordArray.push(word);

        var LanguageTranslatorV3 = require('watson-developer-cloud/language-translator/v3');

        var languageTranslator = new LanguageTranslatorV3({
            version: '2018-05-01',
            iam_apikey: 'swordfish',
            url: 'https://gateway.watsonplatform.net/language-translator/api',
            headers: {
                'Content-Type': 'application/json'
            }
        });

        var parameters = {
            "text": wordArray,
            "model_id": "es-en",
            "source": "es",
            "target": "en"
        };

        let translationsArray = [];

        languageTranslator.translate(
            parameters,
            function (err, response) {
                if (err) {
                    console.log('error:', err);
                } else {
                    response.translations.forEach(function (translation) {
                        console.log(translation.translation);
                        translationsArray.push(translation.translation);
                    });
                    console.log(translationsArray);

                    admin.firestore().collection('Dictionaries').doc('Spanish').collection('Words').doc(word).collection('Translations').doc('English').set({
                        translationsArray: translationsArray,
                        language: 'en',
                        longLanguage: 'English'
                    })
                        .then(function () {
                            console.log("Translations written to database.");
                        })
                        .catch(function (error) {
                            console.error(error);
                        });

                }
            }
        );
    }
    return 0;
});

我还编写了相同的云函数,称为牛津英语词典进行翻译.完美运行,将翻译内容写入数据库:

I also wrote the same cloud function calling the Oxford English Dictionary for the translation. This works perfectly, writing the translation to the database:

exports.Oxford_EStranslateEN = functions.firestore.document('Users/{userID}/Spanish/Translation_Request').onUpdate((change, context) => {
    if (change.after.data().word != undefined) {
        let word = change.after.data().word;
        let options = {
            uri: 'https://od-api.oxforddictionaries.com/api/v1/entries/es/' + change.after.data().word + '/translations%3Den', // translations=es
            headers: {
                "Accept": "application/json",
                'app_id': 'groucho',
                'app_key': 'swordfish'
            },
            json: true
        };
        let translationsArray = [];
        return rp(options)
            .then(function (wordObject) {
                wordObject.results.forEach(function (result) {
                    result.lexicalEntries.forEach(function (lexicalEntry) {
                        lexicalEntry.entries.forEach(function (entry) {
                            entry.senses.forEach(function (sense) {
                                if (sense.translations) {
                                    sense.translations.forEach(function (translation) {
                                        translationsArray.push(translation.text);
                                    });
                                } // close if
                                else {
                                    if (sense.subsenses) {
                                        sense.subsenses.forEach(function (subsense) {
                                            if (subsense.translations) {
                                                subsense.translations.forEach(function (translation) {
                                                    translationsArray.push(translation.text);
                                                }); // close forEach
                                            } // close if
                                            else {
                                                // console.log("No Translation");
                                            } // close else
                                        }); // close forEach
                                    } // close if
                                } // close else
                            }); // close forEach
                        }); // close forEach
                    }); // close forEach
                }); // close forEach
                translationsArray = [...new Set(translationsArray)]; // removes duplicates
                return admin.firestore().collection('Dictionaries').doc('Spanish').collection('Words').doc(word).collection('Translations').doc('English').set({
                    translationsArray: translationsArray,
                    source: 'OED',
                    dateAdded: Date.now(), // timestamp
                    longLanguage: 'English',
                    shortLanguage: 'en',
                    word: word
                })
                    .then(function () {
                        // console.log("Document written.");
                    })
                    .catch(function (error) {
                        console.log("Error writing document: ", error);
                    })
            })
            .then(function () {
                // console.log("Document written for Oxford_EStranslateEN.");
            })
            .catch(function (error) {
                console.log("error: " + error);
            });
    } // close if
    // return 0;
});

一个区别是,我使用 rp (请求承诺)通过HTTP请求调用了OED.我叫 return rp(options).显然,这将返回一个承诺,并且明确返回了该承诺.问题似乎是在Google版本中,当我调用Google Translate时我没有返回诺言,而IBM Watson返回了一个回调而不是诺言,并且我没有返回.

One difference is that I call the OED via an HTTP request, using rp (request-promise). I call return rp(options). This clearly returns a promise, and the promise is explicitly returned. The problem seems to be that in the Google version I'm not returning the promise when I call Google Translate, and IBM Watson returns a callback, not a promise, and I don't return that.

推荐答案

Firebase JavaScript(Web)SDK .set 方法返回一个诺言,即该诺言已经存在.请参阅设置文档在线文档

The Firebase JavaScript (Web) SDK .set method returns a promise, i.e., the promise is already there. See Set A Document online documentation.

// Add a new document in collection "cities"
db.collection("cities").doc("LA").set({
    name: "Los Angeles",
    state: "CA",
    country: "USA"
})
.then(function() {
    console.log("Document successfully written!");
})
.catch(function(error) {
    console.error("Error writing document: ", error);
});

您可能会发现async/await更易于使用(更直观).在这种情况下,您将执行以下操作:

You might find async/await easier to use (more intuitive). In that scenario, you would do something like:

async function writeDocument(obj){
  var writeOperation = await db.collection("cities").doc("LA").set(obj);
  //now this code is reached after that async write
}

这篇关于如何从Firebase Firestore set()调用中返回承诺?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆