Как вернуть обещание от вызова set () Firebase Firestore? - PullRequest
0 голосов
/ 15 января 2019

Это продолжение моего вопроса /10204235/google-translate-api-i-firebase-firestore-ubivayt-drug-druga. Даг Стивенсон сказал, что мне нужно вернуть свои функции. Мы смотрели его видео Learn JavaScript Promises (Pt. 3) for sequential and parallel work in Cloud Functions несколько сотен раз ...

Я работаю с двумя функциями. Во-первых, вызов Google Translate, теперь возвращает перевод. Вторая функция - это вызов Firestore set(), чтобы записать перевод в базу данных. set() работает, если я не делаю вызов Google Translate, но вместе они терпят крах. В частности, если я вызываю Firebase set(), тогда выполняется функция Google Translate, мы видим Result1 и ничего более. Другими словами, вызов базы данных перестает кодировать толкание перевода в 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 Translate никогда не вызывается) и ничего не записывается после «text».

Я не понимаю, что делает const finalPromise. Это похоже на неиспользованную константу.

Мы прочитали Почему API Firebase асинхронный? и попробовали этот код:

      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 не регистрируется и ничего не записывает в базу данных.

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

Я также написал ту же облачную функцию, вызывая Оксфордский словарь английского языка для перевода. Это отлично работает, запись перевода в базу данных:

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

Единственное отличие состоит в том, что я вызываю OED через HTTP-запрос, используя rp (запрос-обещание). Я звоню return rp(options). Это ясно возвращает обещание, и обещание возвращается явно. Кажется, проблема в том, что в версии Google я не возвращаю обещание при вызове Google Translate, а IBM Watson возвращает обратный вызов, а не обещание, и я его не возвращаю.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Я получил это работает:

exports.Google_EStranslateEN = functions.firestore.document('Users/{userID}/Spanish/Translation_Request_Google').onUpdate((change, context) => {
  if (change.after.data().word != undefined) {
    // copied from https://cloud.google.com/translate/docs/quickstart-client-libraries
    // Imports the Google Cloud client library
    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,
    });
    const word = change.after.data().word; // The word to translate
    const options = {
      from: 'es', // the source language
      to: 'en', // the target language
      format: 'text' // HTML vs. plain text
    };
    let translationArray = [];  // clear translation array
    return translate.translate(word, options)  // this return is critical
    .then(function(results) {
      let translation = results[0];
      translationArray.push(translation);
      admin.firestore().collection('Dictionaries').doc('Spanish').collection('Words').doc(word).collection('Translations').doc('English').set({
        translationArray: translationArray,
        language: 'en',
        longLanguage: 'English'
      });
    })
    .then(function() {
      console.log("Write succeeded!");
    })
    .catch(function(error) {
      console.error(error);
    });
  } // close if
});

Ключ должен был вернуть функцию перевода:

    return translate.translate(word, options)

Облачная функция также работает быстрее.

Дуг Стивенсон ответил на мой предыдущий вопрос :

Вы не возвращаете обещание, которое разрешено, когда все асинхронные работы завершено. Если вы этого не сделаете, Cloud Functions предполагает, что все Ваша работа завершена, и будет ограничивать все ресурсы, и любой ожидающие работы будут закрыты.

Обещание, возвращаемое translate.translate().then().catch(), выполняется игнорируются. Ваш вложенный вызов admin.firestore()...set() имеет аналогичный проблема. Недостаточно просто звонить then() и catch() на каждом обещание, потому что then() и catch() оба возвращают еще одно обещание.

Похоже, фраза «вернуть обещание» используется здесь двумя способами. Сказать, что translate.translate() возвращает обещание, отличается от того, что мне нужно вернуть обещание путем кодирования return translate.translate(). Возможно, было бы яснее, если бы Дуг сказал «вернуть функцию» вместо «вернуть обещание»?

Мне также не ясно, нужно ли мне возвращать эту функцию:

return admin.firestore()...set({

Работает одинаково с return.

0 голосов
/ 16 января 2019

Метод Firebase JavaScript (Web) SDK .set возвращает обещание, то есть обещание уже существует. См. Установка документа электронная документация.

// 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 (более интуитивно понятный). В этом случае вы бы сделали что-то вроде:

async function writeDocument(obj){
  var writeOperation = await db.collection("cities").doc("LA").set(obj);
  //now this code is reached after that async write
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...