こんにちは!久しぶりにQiita記事を書きます!
今回は現在地から近い・安いラブホテル検索アプリを開発したので、紹介&実装の一部を今後振り返れるよう書き記します!!
https://apps.apple.com/jp/app/ラブホテル簡単検索-ホテルイキタイ/id1524262826
是非、覗いて見てください…笑
#作った理由#
- 検索時の情報過多を解消するアプリを作りたいと思った。
(ex.グルメアプリなど多くの情報を入力してそれに適したものを表示してくれるが、その初めの入力作業が億劫に感じた。) - Pinterestのような、まずレコメンドを表示する。探索と検索両方を合わせ持つアプリを他の分野で作りたいと思った。
- モバイルに適応している(UI、UX)ラブホテル検索サービスがあまりないと感じたから。
上記の点よりラブホテルの検索アプリを作ろうと決めました!!
#GAS(Google Apps Script)とFireStore連携
アプリを作るにあたってまず、都内のラブホテルの情報をGoogleスプレッドシートに書き込み、書き込んだ情報をFireStoreにコレクションとして追加しました。
ここでは2つのスプレッドシートを作りました。
一つ目はホテルの簡易な情報、二つ目は詳細な情報です。
これらをFireStoreに追加します。下記の記事を参考にさせていただきました。詳しい手順はこちらをみていただければと思います。
https://medium.com/@m_coder/バックエンドの知識がない自分がfirestore-googleappsscriptで簡易dbを構築した話-def690bb3c4d
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getDataRange().getValues();
var START_ROW = 1
var START_COL = 1
function getSheetValue(sheet) {
// 1行目(フィールド)の値を取得
var fieldRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());
var fieldRowValues = fieldRange.getValues();
var fields = fieldRowValues[0];
var rowValues = [];
var jsonArray = [];
var range = sheet.getRange(START_ROW, START_COL, sheet.getLastRow() - START_ROW + 1, sheet.getLastColumn())
var values = range.getValues();
for(var i = 0; i < values.length; i++) {
// 1行のデータをpush
var rowValue = values[i];
var json = new Object();
for(var j = 0; j < fields.length; j++) {
json[fields[j]] = rowValue[j]
}
jsonArray.push(json)
}
return jsonArray;
}
function firestoreCertification() {
var certification = {
"email": "{client_emailの値}",
"key": "-----BEGIN PRIVATE KEY-----\n{private_keyの値}\n-----END PRIVATE KEY-----\n",
"projectId": "{project_idの値}"
}
return certification;
}
function createFirestoreDocuments() {
var arrayData = getSheetValue(sheet);
arrayData.forEach(createDocument)
}
function createDocument(item) {
var certArray = firestoreCertification();
var firestore = FirestoreApp.getFirestore(certArray.email, certArray.key, certArray.projectId);
firestore.createDocument('HotelList',item);
}
これでcreateFirestoreDocuments関数を実行することでFireStoreに書き込みが行われます。
スプレッドシートに記入していた内容をドキュメントとして書き込むことができました!
新たにスプレッドシートに追加で書き込んでFireStoreにドキュメントを追加したい場合は
//新たに追加し始める行
//ex.新たに10行目からスプレッドシートに書き込んだ場合
var START_ROW = 10
上記のコードの場合START_ROW
の値を変えることで可能です。
#CloudFunctionsで全体に書き込みしたい#
上記のスプレッドシートの画像を見ていただけると分かるのですが、2枚目のホテルの詳細が書いてあるスプレッドシートのフィールドにhotelIdがあると思います。
このhotelIdはHotelListコレクションのドキュメントIDを値としています。
※HotelListはスプレッドシート画像1枚目のデータをFireStoreに書き込んだコレクションです。
上記の画像のように該当するhotelIdをクエリして詳細ページに遷移しています。
class HotelDetailModel {
var items = [HotelDetailItem]()
weak var delegate: HotelDetailModelDelegate?
func fetchHotelDetail(with hotelId: String) {
let query = Firestore.firestore().collection("HotelDetail").whereField("hotelId", isEqualTo: hotelId)
query.getDocuments { [weak self] (snapshot, error) in
guard let `self` = self else { return }
if let snapshot = snapshot {
self.items = snapshot.documents.map {HotelDetailItem(from: $0.data(), docId: $0.documentID)}
}
self.delegate?.didFetchHotelDetail(with: error)
}
}
}
※一部抜粋
前置き大変長くなって申し訳ありません。とにかくHotelDetailそれぞれのドキュメントに該当するhotelIdをCloudFunctionsでまとめて追加したいという話です…笑
#TypeScriptで実装#
導入はこちらを参考にしました。
https://qiita.com/star__hoshi/items/7dcf5970d28a7ff239fb
以下hotelIdを追加するために書いたコードです。
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
admin.initializeApp(functions.config().firebase)
const db = admin.firestore()
type DocumentReference = admin.firestore.DocumentReference
interface HotelItem {
readonly address: String
readonly area: String
readonly imageUrl: String
readonly name: String
readonly restMin: number
readonly stayMin: number
ref: DocumentReference
}
interface HotelDetail {
readonly address: String
readonly name: String
readonly access: String
readonly callNumber: number
readonly hotelUrl: String
readonly roomNum: number
readonly imageUrlList: String
readonly restPlan: String
readonly stayPlan: String
hotelId: String
}
export const requestHotelIdGain = functions.region('asia-northeast1').https.onRequest(async (req, res) => {
try {
const result = await fetchHotelId()
return res.status(200).send(result)
} catch (error) {
return res.status(400).send(`Failed ${error}`)
}
})
async function fetchHotelId() {
const hotelListQuery = db.collection('HotelList')
const hotelDetailQuery = db.collection('HotelDetail')
const hotelListSnap = await hotelListQuery.get()
const hotelDetailSnap = await hotelDetailQuery.get()
const batch = db.batch()
hotelListSnap.docs.forEach(doc => {
const hotelItem = doc.data() as HotelItem
hotelDetailSnap.docs.forEach(detailDoc => {
const hotelDetail = detailDoc.data() as HotelDetail
if (hotelItem.name === hotelDetail.name) {
batch.update(detailDoc.ref,{hotelId: doc.id})
}
})
})
await batch.commit()
return new Promise<string>(resolve => resolve(`yeahhh`))
}
やったことはHotelListとHotelDetailのコレクションを取ってきて、
それぞれforEachで一つ一つのドキュメントにif (hotelItem.name === hotelDetail.name)
で同じホテルの名前であったときに、一致したHotelDetailのドキュメントに一致したHotelListのdocumentIdを書き込んでいます。
batch.update(detailDoc.ref,{hotelId: doc.id})
無事hotelIdフィールドに該当するdocumentIdが追加されました!!
#最後に#
最後まで見ていただきありがとうございます!!
間違っている点ありましたらご指摘していただけると幸いです!
他にも苦戦した点も後々書こうかと思います!
正直、今回のアプリは使う場面も限られており且つ、多くの人に使ってもらえるかは…ですが、今後も自分で作っていきたいなと思いました!!