Firebaseはすごい(こなみかん)。
・Firebaseってなに
Firebaseとは、Googleが買収してしまった提供するmBaaSのひとつである。以前紹介したNCMBと似たようなやつなので、mBaaSについての説明は割愛する。
・ここがすごい
データベースに変更があると、直ちにそれをクライアント側に通知してくれる。
・つかいかた
今回はJavascriptでの使い方を紹介していく。
・準備
まずはFirebaseのコンソールを開き、「アプリを追加」→「ウェブアプリにFirebaseを追加」から初期化コードをコピーして、使いたいページの<head>
タグの中にペーストする。おわり。なんかこんな感じのコードである。ほげほげふがふがしてるところはアプリに固有の値が入る。
<script src="https://www.gstatic.com/firebasejs/5.7.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "ほげほげ",
authDomain: "ふがふが.firebaseapp.com",
databaseURL: "https://ふがふが.firebaseio.com",
projectId: "ふがふが",
storageBucket: "ふがふが.appspot.com",
messagingSenderId: "ぴよぴよ"
};
firebase.initializeApp(config);
</script>
・データベースの基本操作
ref(path)
でpath
への参照を取得し、そこからの操作は基本的に以下の4つ。
書き込み | set |
更新 | update |
読み取り | on およびonce |
削除 | remove か、null を書き込む |
では、ソースコードの例を示していこう。
・書き込み
var db=firebase.database();
db.ref('test1').set("hoge");
db.ref('test2').set({
"fuga1":"fuga",
"fuga2":"fugafuga"
});
こうなる。
・更新してみる
db.ref('test2').update({
"fuga2":{
"fuga2_1":"fugafuga_fuga",
"fuga2_2":"fugafuga_fugafuga"
}
});
//値を直接指定してupdateはできない
db.ref('test3').update("piyo???"); //→エラー
//存在しない要素へのupdateは可
db.ref('test4').update({
"piyo":"piyo????"
});
こうなる。
コード中にも書いた通り、update
の引数に直接、値を指定しようとすると、
Error: Reference.update failed: First argument must be an object containing the children to replace.
とエラーになり(なんでそういう仕様にしたんだろうか)、また、存在しない要素をupdate
すると要素が追加できる。あと、update
の代わりにset
を使ってしまうと、更新したかった要素以外の兄弟要素がすべて無へと還元されてしまうので気を付けよう。
ちなみにset
とupdate
の第二引数には関数を指定することができ、書き込みの成否を受け取ることができる。このように書けばよい。
db.ref('test5').update({
"hoge2": "hogeeeeee"
},function(e){
if(e==null){
//成功時の処理
console.log("Success!");
}else{
//失敗時の処理
console.log(e);
}
});
・読み取り
ここがFirebaseの肝である。前述の通り、読み取りメソッドはon
およびonce
の2つある。字面からなんとなくわかる通り、once
は一回だけ読み取り、on
は要素に更新があるたびに(子要素や孫要素など、より下の階層の更新でも)呼び出される。
したがって、単純に読み取りたいだけならば、once
を用いて
db.ref('test2').once('value',function(obj){
var key=obj.key; //オブジェクトのキーを取得
var data=obj.val(); //オブジェクトを取得
console.log(key);
console.log(data);
});
とすることで読み取りができる。この場合は、
test2
{
"fuga1": "fuga",
"fuga2": {
"fuga2_1": "fugafuga_fuga",
"fuga2_2": "fugafuga_fugafuga"
}
}
という出力が得られる。
また、on
メソッドにおいては第一引数の値によって検知する更新の種類を指定できる。
value |
どんな更新であってもオブジェクトそのものを取得する |
child_added |
子要素が追加されたとき、追加された子要素を取得する |
child_changed |
子要素が変更されたとき、変更された後の子要素を取得する |
child_removed |
子要素が削除されたとき、削除される前の子要素を取得する |
気を付けるべきは、ここで取得される子要素はあくまで参照の直下の子要素であるという点である。今回の例でいえば、たとえば
db.ref('test2').on('child_changed', function (obj) {
console.log(obj.val());
});
というようなコードを書いたとすると、"fuga1"
の値が"fu"
に変更されたときは"fu"
が返るが、"fuga2_2"
の値が"fugaaaaa"
に変更されたときは、"fugaaaaa"
が返ってくるのではなく"fuga2"
全体のオブジェクトが返ってくる。言葉ではわかりにくいので図にするとこうだ。
・応用編
以上で基本操作は終わりなので、使えると便利な応用編に入ろう。
・push
push
は、データベース上に一意なキーを持つオブジェクトへの参照を生成する。雑に言えば、(たぶん)絶対被らないID生成メソッドだと思えばいい。
次のコードを呼び出してみると、
var pushed=db.ref('test6').push();
var id=pushed.key; //IDを取得
pushed.set("hoge!?");
何やら怪しげな文字列が出現する。
実はこの文字列は120ビットのデータに相当し、そのうち先頭48ビットはタイムスタンプから、残り72ビットはランダムに生成される。タイムスタンプに基づく48ビット分によって、この文字列は辞書順に並べた時にきちんと時系列順になるように設計されているのだ(このIDはクライアント側が生成しているので厳密には時計のズレによって前後する可能性はあるが、ほとんど時系列順になると思ってよい)。
これが威力を発揮するのは複数端末がデータベースにアクセスするような仕組みを作るときである。クライアント間でIDが被らないよう示し合わせる必要もなければ、時系列で並べ替えるためのデータを含めてやる必要もないのだから楽なものである。
さらに、このIDは上のソースコード中にあるようにkey
プロパティで取得できるので、いろいろなデータを分散させて保存することも可能になる。こうすることでクライアント側で読み込む必要があるデータを最小限に抑えることができるので、是非活用したい。
・実践編
以上を踏まえて雑な掲示板でも作ってみよう。とか思って15分くらいで書いたのがこれである。
<html>
<head>
<title>Chat Sample</title>
<!-- ここにFirebaseの初期化コードをペースト -->
<style> /* cssで最低限の体裁を整える */
#e_content {
height: 100px;
width: 100%;
}
#container {
width: 600px;
margin: 0 auto;
}
#form {
width: 100%;
}
#main {
padding: 15px;
border: 1px #333 solid;
max-height:450px;
overflow-y:scroll;
}
.msg {
border-bottom: 1px dashed #666
}
</style>
</head>
<body> <!-- html部分 -->
<div id="container">
<div id="main">
</div>
<div>
<table id="form">
<tr>
<td>Your Name</td>
<td><input id="e_name"></td></tr>
<tr>
<td>Content</td>
<td><textarea id="e_content"></textarea></td>
</tr>
<tr>
<td></td>
<td><Button onclick="submit()">Submit</Button></td>
</tr>
</table>
</div>
</div>
</body>
<script> //制御部分
var db = firebase.database();
db.ref('msg').on("child_added", function(obj) {
var data = obj.val();
var name = data.name;
var content = data.content;
var e = document.createElement("div");
e.setAttribute("class", "msg");
e.innerHTML = "<p class='name'>Name: " + name + "</p><p class='content'>Content: " + content + "</p>";
var box=document.getElementById("main");
box.appendChild(e);
box.scrollTop=box.scrollHeight;
})
function submit() {
var el_n = document.getElementById("e_name")
var el_c = document.getElementById("e_content")
var name = el_n.value,
content = el_c.value;
if (name == "" || content == "") {
alert("Please fill out the blank!");
return;
}
el_c.value = "";
db.ref('msg').push().set({
"name": name,
"content": content
});
}
</script>
</html>
どうだろうか。Javascript部分は30行もない程度、全体でも100行に満たないが、これでもきちんと掲示板としての役割は果たす程度のモノができているはずである。実際に動かしたい場合はここにこれと同じものを置いているので、試してみてほしい(記事の感想をお待ちしております)。
以上。Firebaseを使っていると、FirebaseよりJavascriptで躓くことの方が多い。Javascriptはクソ