Monacaのサンプルアプリである「フォトシェアアプリデザインテンプレート」にバックエンド機能を実装する連載の第6回目。今回はフォロー/フォロワーの仕組みを作ります。
その1:認証編
その2:プロフィール編集
その3:写真アップロード
その4:写真検索
その5:いいね/コメント
データの管理法について
一般的なRDBMSで考えた場合、次のようなテーブル構成になるかと思います。
- User : ユーザ情報が入ったテーブル
- Follow : フォロー/フォロワー情報が入ったテーブル
FollowテーブルにはフォローしたユーザIDとフォローされたユーザIDが入り、相互にUserテーブルを参照します。しかし、この場合の問題点としてユーザがフォローするごとにFollowテーブルにデータが追加されていき、フォロー情報から写真データを取得する処理が重たくなっていくという点が挙げられます。
RDBMSではないmBaaSでは上記のような方法ではなく、ユーザ情報にfollowsというカラムを追加し、そこにフォローしたユーザのobjectIdを配列形式で追加していく方法で対応したいと思います。この場合、フォロー数が増えてもデータのレコード数は増えないので重たくなりません。
mBaaSではリレーションという仕組みも用意されているのですが、直接連結しているクラス(たとえば、フォロー情報→ユーザ情報)しか取得できません。今回、本当に必要なのは写真クラスのデータになりますので、フォロー情報とユーザ情報をリレーションで結ぶのはよくありません。
フォローしているユーザの数は次のようにして取得できます。
user.follows ? user.follows.length : 0
フォロワーは次のように取得します。Userクラス内で、followsカラムの中に自分自身のobjectIdが入っているデータの数を数えるという方法です。
ncmb.User
.equalTo('follows', user.objectId)
.count()
.fetchAll()
.then((result) => {
// result.countがフォロワーの数
})
画面遷移について
フォローは、ユーザ情報が表示されるページで行うことができます。このための処理を、写真を追加した時に実行される appendPhoto() 内に追加します。
const appendPhoto = (dom, photo) => {
// 省略
$(dom).find('.profile_image').on('click', (e) => {
$('#nav')[0].pushPage('user.html', {animation: 'slide', data: {user: photo.user}});
});
}
ユーザ情報ページに画面遷移した際に、すでにフォローしているユーザだった場合は Follow の文字を Unfollow にします。
if (current_user.follows && current_user.follows.indexOf(user.objectId) > -1) {
$(dom).find('.follow').text('Unfollow');
}
また、自分のページだった場合はフォローボタンを無効にします。
if (user.objectId == current_user.objectId) {
$(dom).find('.follow').attr('disabled', true);
}
フォロー処理について
フォロー処理は次のように実装します。すでにフォローしていればフォローを解除し、フォローしていなければフォローするという流れです。
$(dom).find('.follow').on('click', (e) => {
let follows = current_user.follows;
if (!follows) {
// まだデータがない場合は初期化
follows = [user.objectId];
} else {
// すでにフォローしているかチェック
if (follows.indexOf(user.objectId) > -1) {
// フォローしていればアンフォロー
follows = follows.filter((u) => {
return (u !== user.objectId);
});
} else {
// フォローしていなければフォロー
follows.push(user.objectId);
}
}
current_user
.set('follows', follows)
.set('authData', {}) // ないとエラーになります
.update()
.then(() => {
// フォロー状態をチェックしてボタンの文字を変更
if (current_user.follows && current_user.follows.indexOf(user.objectId) > -1) {
$(dom).find('.follow').text('Unfollow');
}else{
$(dom).find('.follow').text('Follow');
}
})
});
タイムライン表示について
タイムラインには、自分の写真とフォローしているユーザの写真を表示します。
実装方法は、フォローしているユーザのobjectIdを複数指定して、写真クラスに対してinで検索します。
タイムラインには写真のアップロード主であるユーザ名を表示しますので、includeを使ってユーザ情報も同時に取得するようにしています。
const loadTimeline = () => {
const Photo = ncmb.DataStore('Photo');
const follows = current_user.follows || [];
follows.push(current_user.objectId)
Photo
.limit(10)
.include('user')
.in('userObjectId', follows)
.order('createDate')
.fetchAll()
.then((photos) => {
for (let i = 0; i < photos.length; i += 1) {
const photo = photos[i];
timelinePhotos[photo.objectId] = photo;
}
});
}
ここまでの処理でフォロー/アンフォロー処理ができあがりました。ソーシャル系サービスではよく求められる機能になりますので、実装方法を参考にしてもらえれば開発がスムーズになるかと思います。データを配列で持ち、行数を減らすのはmBaaSのスキーマレス型データベースではよく使われる方法になりますので、応用できる機会は多いはずです。
ここまでのソースコードはNCMBMania/photoshare at v0.6にアップロードしてあります。実装時の参考にしてください。