0

更新されたドキュメントをロードする「onUpdate」関数を作成しようとしています。次に、ワイルドカードによって受け取ったデータを使用して、別のドキュメントをロードしたいと考えています。要約すると、更新されたドキュメントと同じコレクションにある別のドキュメントにアクセスしたいと思います。

私は欲しい:/userProfiles/{doc1}/employees/{doc2}そして/userProfiles/{doc1}

両方を取得できますが、一方のデータを使用しようとすると、前のデータが読み取られず、ReferenceError.

最終的な目標は、これらの両方のドキュメントを使用して、nodemailer で電子メールを送信することです。助けてくれてありがとう。


const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require('nodemailer');
admin.initializeApp();

exports.testLog = functions.firestore
  .document('/userProfiles/{doc1}/employees/{doc2}')
  .onUpdate((change, context) => {
    var info = [];
    const doc1 = context.params.doc1;
    const doc2 = context.params.doc2;

    const db = admin.firestore();

    return (
      db
        .collection("userProfiles")
        .doc(`${doc1}`)
        .get()
        .then(doc => {
          var email = doc.data().email;
          var phone = doc.data().phone;

          info.push(doc.data());

          console.log(email, phone); // sees and gets info

          return email, phone;
        }),
      db
        .collection("userProfiles")
        .doc(`${doc1}`)
        .collection(`employees`)
        .doc(`${doc2}`)
        .get()
        .then(doc => {
          info.push(doc.data());

          var Status = doc.data().Status;

          console.log(phone, `${Status}`); //phone is undefined

          if (`${Status}` === "Alarm") {
            // replace with variables from the users settings page

            console.log(`${info.phone}`); // phone is undefined

            let transporter = nodemailer.createTransport({
              host: "smtp.gmail.com",
              port: 587,
              secure: false, 
              auth: {
                user: "xxxxxx@gmail.com",
                pass: "xxxxxxxxxx"
              }
            });

            // send mail with defined transport object
            let mailOptions = {
              from: '"Fred Foo " <foo@example.com>', 
              to: `${info.phone}`,  // tried phone as well
              subject: "Hello ✔", 
              text: "216+?", 

            };

            transporter.sendMail(mailOptions, error => {
              if (error) {
                return console.log(error);
              } else {
                return console.log("message sent");
              }
            });
          }

          console.log(Status);
          // return
          return console.log("im after the if statement. No alarm triggered");
        })

        .then(message => console.log(message.sid, "success"))
        .catch(err => console.log(err))
    );
  });

ファイアストア

サブコレクション

したがって、これら2つの画像で電話番号とステータスを取得したい 返されるエラー:

ReferenceError: 電話が定義されていません

4

1 に答える 1

2

問題の原因となる期待どおりに機能していないことが 2 つあります。

  • promise の処理は実際には期待どおりにデータを渡しません。特に、変数 phone と email は 1 つの promise ハンドラにのみ存在し、スコープがグローバルではないためphoneemailpromise チェーンに渡されません。 .

  • コンテンツは関数自体で渡されるため、実際には 2 番目のドキュメントを読む必要はありません。これにより、実際に行っている全体的な作業が大幅に簡素化され、2 番目のデータベース呼び出しをスキップできるため、最初のポイントの処理がほとんど簡単になります。

わかりやすくするためにメッセージ コードを省略し、ほとんどのログ メッセージを残した次のコードを見てください。

exports.firestoreOnUpdateTest = functions.firestore
    .document('/userProfiles/{doc1}/employees/{doc2}')
    .onUpdate((change, context) => {
  // var info = []; I have removed this list, it is not necessary
  const doc1 = context.params.doc1;
  // no need to get the doc2 parameter, as we are handed the doc itself by the function call.

  const doc2content = change.after.data();

  const db = admin.firestore();

  return (
    db
      .collection("userProfiles")
      .doc(`${doc1}`)
      .get()
      .then(doc => {
        const doc1content = doc.data();
        const email = doc1content.email;
        const phone = doc1content.phone;

        console.log(email, phone); // sees and gets info

        console.log(`No need to fetch doc2, as I already have it: ${JSON.stringify(doc2content)}`);
        const Status = doc2content.Status;

        console.log(`email for user is still: ${email}`); // email is now defined
        console.log(phone, `${Status}`); // phone is now defined

        if (`${Status}` === "Alarm") {
          console.log(`${phone}`); // phone is now defined

          return console.log('message would be sent here - code omitted')
        }

        console.log(Status);

        return console.log("im after the if statement. No alarm triggered");
      })
      .catch(err => console.error(err))
  );
});

Status新しいバージョンでは、パラメーターを含め、トリガーしたドキュメントのコンテンツを保存するだけです。次に、ツリーの上位レベルで、必要なコンテンツを含むドキュメントを取得します。そのドキュメントが返されたら、それを処理して doc2 のデータと結合します。これで、すべてのフィールドが定義されました (もちろん、データベース オブジェクトが整形式であることが前提です)。

明らかなログ メッセージが存在する場合、メッセージング コードは正しく再挿入されます。

最後に、info今は必要ないと思うリストを削除しました。代わりに、既に手元にあるデータからメッセージ自体を構築する際に、必要なものを構築することをお勧めします。とはいえ、元のコードは正しく (つまり、リストとして) アクセスしていなかったので、さらに混乱させた可能性があります。

最後に、質問が主に未定義のフィールドに焦点を当てているため、Nodemailer モジュールの使用については触れていませんが、元のコードも完全に正しくない可能性があると思われますsendMail()。そのawait呼び出しで(そして関数全体を作るasync)ので、それをもっと詳しく見る必要があります。

于 2019-10-28T18:00:20.530 に答える