前回からの続きです。
firestoreの操作がどうしてもできないのでチュートリアルを学ぶことにしました。
firebaseのメニューからドキュメント>サンプルを選択し、FriendlyEatsというサンプルを選択します。
チュートリアルを実践します。
別アプローチ
しかしチュートリアルを実践してもそのファイルが複雑で、求めていた部分(Firestoreのデータベースから情報を取得して表示)がわからなかったので別のアプローチをとることにしました。
ネット上で似たようなことをしている人を探しましたが、上手くマッチしませんでした。
そこで、半端だったJavascriptを学習し、わかっている部分を修正しました。
そうしたところ、ようやくローカルで動いてfirestoreのデータベースの値が表示できました。
・動いたコード
// Firebase SDKをインポート
const firebase = require('firebase/compat/app');
require('firebase/compat/firestore');
// Firebaseプロジェクトの設定
const firebaseConfig = {
apiKey: "xxx",
authDomain: "xxx.firebaseapp.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
messagingSenderId: "xxx",
appId: "xxx",
};
// Firebaseを初期化
firebase.initializeApp(firebaseConfig);
// Firestoreを初期化
const db = firebase.firestore();
// コレクションからデータを取得して表示
const temperatureDataRef = db.collection('xxx');
temperatureDataRef.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const data = doc.data();
console.log(`MAC Address: ${data.macAddress}, Temperature: ${data.temperature}, timestamp: ${data.timestamp}`);
});
});
・実行結果
[Running] node "/Users/firebase/public/app.js"
MAC Address: 08d1f9e822ec, Temperature: 29.5, timestamp: Timestamp(seconds=1701245474, nanoseconds=113000000)
MAC Address: 08d1f9e822ec, Temperature: 29.5, timestamp: Timestamp(seconds=1701245738, nanoseconds=502000000)
MAC Address: 08d1f9e822ec, Temperature: 29.5, timestamp: Timestamp(seconds=1701275510, nanoseconds=78000000)
MAC Address: 08d1f9e822ec, Temperature: 29.5, timestamp: Timestamp(seconds=1701268643, nanoseconds=32000000)
MAC Address: 08d1f9e822ec, Temperature: 29.5, timestamp: Timestamp(seconds=1701276498, nanoseconds=252000000)
ここから日付の表示形式やhtmlにデータを渡す修正などをしていきます。
Firebaseにデプロイしても動かない
Node.jsはバックエンド、フロントエンドはJavascriptと違うため、上記のコードをデプロイしてもブラウザでは表示を確認できませんでした(上記はNode.js)。
つまり以下のようにズレていたのです。
- 書いていたコード:Node.js
- Code Runnerのデバッガ:Node.js
- Visual Studio Codeのデバッガ:Node.js
- hostingにデプロイすべきコード:フロントエンドJavascript
そのため、コードをフロントエンド用のjavascriptに書き直します。
フロントエンドJavascriptのデバッグ
Chromeの表示>開発/管理>デベロッパーツールからデバッグができます。
アクセス拒否エラー
Node.jsの記述ではデータベースからデータを読み込めていましたが、フロントエンドJavascriptにしてから以下のエラーがブラウザで出ていました。
Uncaught (in promise) FirebaseError: Missing or insufficient permissions. at serializer.ts:153:10 at Eu.onMessage (persistent_stream.ts:581:25) at persistent_stream.ts:461:21 at persistent_stream.ts:514:18 at async_queue_impl.ts:135:7 at async_queue_impl.ts:186:14
Firestoreの設定でセキュリティのルールを変更した覚えはなかったのですが、確認するとfalseになっていたのでtrueに修正しました。
なぜこうなったかというと、ローカルのルートディレクトリのfirestore.rulesが以下のようになっていたからです。
・firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
このファイルの記述がfalseだったので、firebase deploy コマンドで全部をデプロイしたとき、ルールも一緒にfalseに更新されていました。
ようやくデータベースの値が表示できた
上記のルール設定を変更し、デプロイしたところようやくデータベースの値をブラウザで表示できました。
以下はそのコードです。
・index.html
<!DOCTYPE html>
<html>
<head>
<title>Temperature Data</title>
<!-- Firebaseの設定 -->
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.0.0/firebase-firestore-compat.js"></script>
</head>
<body>
<h1>Temperature Data</h1>
<div id="display"></div>
<script src="script.js"></script>
</body>
</html>
・script.js
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "xxx",
authDomain: "xxx.firebaseapp.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
messagingSenderId: "xxx",
appId: "xxx",
};
// Firestoreのタイムスタンプを指定タイムゾーンの時刻にフォーマットする関数
function formatTimestampInTimeZone(timestamp, timeZone) {
const date = new Date(timestamp.seconds * 1000); // FirestoreのTimestampをDateオブジェクトに変換
const formatter = new Intl.DateTimeFormat('ja-JP', {
timeZone: timeZone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
return formatter.format(date);
}
// Firebase、Firestoreを初期化
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
// temperatureDataコレクションからデータを取得して表示
const temperatureDataRef = db.collection('temperatureData');
temperatureDataRef.get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const data = doc.data();
const formattedTimestamp = formatTimestampInTimeZone(data.timestamp, "Asia/Tokyo");
document.getElementById('display').textContent = data.macAddress;
});
});
今後は、すべてのデータを表示、グラフで描画することをやっていきます。