質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.60%

Cloud FunctionとFirestoreでプッシュ通知を送信する(firebase)

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,349

yamady

score 177

いつもお世話になっております。

Cloud FunctionとFirestoreを使ってスマホ用のチャットプッシュ通知を開発しようと考えています。
元々、RealTime Databaseで動いていたものをFirestore用に書き換えているのですが、どうも最初の部分でつまずいてしまいます。。

Cloud Functionでやるとなると、だいぶ勝手が変わってしまうものなのでしょうか。

開発環境は

firebase-functions: ^0.9.1

です。

 エラー内容

TypeError: snapshot.data is not a function

 ソースコード

// message push notification
exports.messagePush = functions.firestore
.document('/rooms/{roomId}/users/{uid}/messages/{messageId}')
.onWrite((snapshot) => {
  console.log('snapshot:', snapshot);

  const item = snapshot.data();
  const userId = item.child("user").child("_id").val();
  const userName = item.child("user").child("name").val();
  const message = item.child("text").val();

  console.log('item', item);
  console.log('userId', userId);

  const userRef = snapshot.params.uid;

  console.log('userRef', userRef);

  const payload = {
    notification: {
      body: userName + ": " + message,
      badge: "1",
      sound: "default"
    }
  }

  if (userId !== userRef) {
    getMessageFcmToken(userRef, function(token) {
      pushToDevice(token, payload);
    });
  }

  var getMessageFcmToken = function(roomId, callback) {
    admin.firestore().collection('users').doc(`${userRef}`)
    .then((snapshot) => {
      console.log('Valu', snapshot.data());
      const token = snapshot.data()['pushToken'];

      if(token == null) {
        console.log("Nothing token");
        return
      }
      console.log("return callback token", token);

      callback(token);
    })
  }

 コンソール結果

下記がconsole.log('snapshot:', snapshot)の結果になります。
snapshotまでは取れているみたいなのですが、なぜか、その先のsnaopshot.data()でエラーが出てしまっています。

snapshot: { data: 
   QueryDocumentSnapshot {
     _ref: DocumentReference { _firestore: [Object], _referencePath: [Object] },
     _fieldsProto: 
      { _id: [Object],
        createdAt: [Object],
        text: [Object],
        user: [Object] },
     _readTime: undefined,
     _createTime: Timestamp { _seconds: 1535164240, _nanoseconds: 45967000 },
     _updateTime: Timestamp { _seconds: 1535164240, _nanoseconds: 45967000 } },
  eventId: '2c233f09-3c86-49f8-9171-c692ea0ecb35-0',
  eventType: 'providers/cloud.firestore/eventTypes/document.write',
  notSupported: {},
  params: 
   { roomId: 'FJG4k7sBe9Pdv4ns0TW9kt01yGo2',
     uid: 'dtsX83vbUtMlmoFJbqcwr6fJKiS2',
     messageId: 'MjSGIWPJe195uIcAdKWE' },
  resource: 'projects/XXXXXXXXXX/databases/(default)/documents/rooms/FJG4k7sBe9Pdv4ns0TW9kt01yGo2/users/dtsX83vbUtMlmoFJbqcwr6fJKiS2/messages/MjSGIWPJe195uIcAdKWE',
  timestamp: '2018-08-25T02:30:40.045967Z' }

 追記(8月25日)

// message push notification
exports.messagePush = functions.firestore
.document('/rooms/{roomId}/users/{uid}/messages/{messageId}')
.onWrite((change, context) => {

  console.log('change', change);

  const document = change.after.exists ? change.after.data() : null;

  console.log('document', document);

  const newDocument = change.after.data();
  console.log('newDocument', newDocument);

  // Get an object with the previous document value (for update or delete)
  const oldDocument = change.before.data();
  console.log('oldDocument', oldDocument);

・・・

ご回答をいただきましたようにトライしてみました。

上記のように、冒頭を書き加えてみたのですが、下記のエラーが出てしまいました。
console.log('change', change);は上と同じものを取得できましたは、exisitsが取得できず止まってしまいました。。

TypeError: Cannot read property 'exists' of undefined

続いて、existsの構文を消してやってみましたが、やはりデータのところでこけてしまいます。

TypeError: Cannot read property 'data' of undefined
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • xenbeat

    2018/08/25 15:12

    念の為、「firebase-functions」SDKのバージョンを追記ください

    キャンセル

  • yamady

    2018/08/25 17:12

    "firebase-functions": "^0.9.1"ですね。古いような気がしてきました・・・。

    キャンセル

  • xenbeat

    2018/08/25 17:14

    > "firebase-functions": "^0.9.1"ですね。→ 他の人が見てもわかるように質問文に追記ください。

    キャンセル

回答 1

checkベストアンサー

+1

使用されているonWriteは、onCreateonUpdateonDelete がトリガーされたときにトリガーされます。
その中に含まれているonUpdateは、すでに存在するドキュメントの値が変更されたときにトリガーされます。
https://firebase.google.com/docs/functions/firestore-events?hl=ja#trigger_a_function

onWriteは、ドキュメントの変更を検知するイベント(onUpdate)を含むので、変更前と変更後のデータ状態を表す2つのスナップショットがあります。
それが以下に示すafterbeforeです。

.onWrite((change) => {
  const newItem = change.after.data();
  const oldItem = change.before.data();

 追記

ご使用のSDKバージョンが<= v0.9.1(ベータ版)ということなので、かなり古いです。
特別な理由がない限り、SDKバージョンを更新してください。

npm install firebase-functions@latest --save
npm install firebase-admin@5.11.0 --save

// firebase-toolsのバージョンも古そうなので、ついでに更新しておきましょう。
npm install -g firebase-tools

そのままのSDKバージョンを選択せざるを得ない場合は、回答した内容では無理なので以下としてください。

.onWrite((event) => {
  const newItem = event.data.data();
  const oldItem = event.data.previous.data();

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/25 17:13

    確かに、ちょこちょこlatestにするようなアラートが出ていたのでバージョンの問題であるような気がしてきました。。(汗

    キャンセル

  • 2018/08/25 17:24

    やはりSDKのバージョンが古すぎますねー。解決策を回答欄に追記しました。

    キャンセル

  • 2018/08/25 19:18

    ご丁寧な解説を頂きましてありがとうございます。バージョンについても追記が必要ですね。

    現在、item.childでつまずいているのですが、おそらくfirestoreでの参照をする際にはこういう書き方をしないんですよね・・・。
    取り急ぎ、最初のところが行けました。本当にありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.60%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る