[ GCP / Firebase ] GCP からも Firebase からも利用可能な Firestore データベース の 作成方法

Google が提供する NoSQL クラウド データベース である Firestore をWeb アプリや モバイルアプリで利用可能な状態の 作成方法 を紹介します。Firestore は GCP プロジェクトとして利用する方法、 Firebase プロジェクトとして利用する方法がありますが、今回は GCP / Firebase 両方のプロジェクトでデータを共有するようなデータベースの 作成方法 を紹介していきます。 Cloud Firestore は、Firebase と Google Cloud からのモバイル、ウェブ、サーバー開発に対応した、柔軟でスケーラブルなデータベースです。 https://firebase.google.com/docs/firestore Firestore は 以下のような 作成方法 があります。 Firebase プロジェクトとして作成し、 Firebase で利用する方法 GCP プロジェクトとして作成し、 GCP で利用する方法 GCP プロジェクトとして作成し、 GCP, Firebase 双方で利用する方法 Firebase で利用することで、モバイルアプリとの連携が容易になり、 GCP で利用することで、 機械学習などの各種 Google Cloud プロダクトとの統合が可能になります。 今回は、その両方を可能にする3番目の 作成方法 を紹介します。 関連記事: 作業の流れ 作業の流れは大まかに以下の 2 ステップになります。 GCP 側作業:接続先となる Firestore データベースの作成 Firebase 側作業:GCP プロジェクトとの紐付け GCP で Firestore データベースを作成 最初に、接続先となる Firestore を作成していきます。以下の URL をクリックして、 Cloud Console を開きます。 https://console.cloud.google.com/firestore/ 今回は “sample-for-blog” という名称の GCP プロジェクトを用いて進めていきます。 Firestore の作成 ( モード選択 ) Firestore を作成するにあたって、モードを選択する必要があります。 注意書きがあるように、ここでの選択は後で変更できないため、注意深く選択することが重要です。 ざっくりいってしまうと、モバイルアプリからのアクセスをする可能性がある場合は「ネイティブモード」を選択する、という感じでしょうか。逆に、App Engine で Python 2.7 や PHP 5.5 といった 少し古い環境 で用いる場合は「 Datastore … Read more

[Python3] 年月日などの情報から日時オブジェクト datetime を作成する方法

Python で日時を扱う際に datetime オブジェクトを用いると、オブジェクト同士の比較や、時差を考慮することができるようになるので大変便利です。日付を表現した文字列から datetime に変換するサンプルは数多く見つけることができましたが、イチから作成する方法はあまり紹介されていないようだったので紹介します。 環境:Python 3.9 Python datetime について まずは、Python における日時オブジェクトである datetime について簡単に触れていきます。 Python における日時オブジェクトである datetime は、Aware と Naive という2つに分類されます。 Aware: タイムゾーンなどの付加情報をもつため、解釈の余地のない特定の実時刻を表現 Naive: タイムゾーンなどの付加情報をもたないため、多少曖昧ともいえる時刻を表現 また、datetime で取り扱うことができる型は以下の通りです。 date 日付:年、月、日からなる日付 time 時刻:時、分、秒、ミリ秒、 tzinfo からなる時刻 datetime 日付+時刻:date と time を組み合わせたもの timedelta 時間差(経過時間): date, time, datetime について、2つのインスタンス間の時間差 tzinfo タイムゾーン情報: datetime, time で用いるタイムゾーン情報 timezone タイムゾーン:tzinfo に基づいた時刻を UTC からのオフセットとして実装 datetime — 基本的な日付型および時間型 厳密な時刻を扱う必要がない場合は、 Naive が簡素に扱えそうです。ここでは、Aware か Naive かを意識して日時オブジェクトを作成していきます。 datetime オブジェクトの作成 それでは、実際に datetime オブジェクトを作成していきます。まずは、より簡単に作成することができる Naive から始めます。対話型 Python を使ってすすめていきます。 時差を意識しない Naive オブジェクトの作成 対話型 Python を起動します。 年、月、日 を指定して作成してみます。 次に、年月日に加え、時分秒まで指定してみます。 なお、時分秒ミリ秒は省略可能で省略するとゼロとして扱われますが、年月日は省略不可となります。 続いて、より正確な日時を表す Aware オブジェクトを作成していきます。 時差を意識した Aware オブジェクトの作成 Aware オブジェクトを作成するためには、 tzinfo を指定して作成する必要があります。まずは、 UTC で作成してみます。 次に、同じ時刻を JST として作成してみます。JST として作成するためには、datetime のサブクラスである timezone を使って JST を表現する必要があります。以下にあるように、UTC からの固定の時差を指定することで表現することができます。用途に応じて timezone の作成方法に違いがあります。ここでは、後者の方法で進めていきます。 timezone クラスは tzinfo のサブクラスで、各インスタンスは UTC からの固定されたオフセットで定義されたタイムゾーンを表しています。 … Read more

[SwiftUI]@Stateの代わりに@ObservedObjectを使い、Child Viewの状態変化をParent Viewから参照可能にする

SwiftUIでは、@Stateを使うことで@Stateとして宣言したプロパティの値が変更されるとリアルタイムに更新され大変便利なのですが、@StateにはViewの本体、またはViewから呼び出されるメソッドからしかアクセスすることができません。 You should only access a state property from inside the view’s body, or from methods called by it.  https://developer.apple.com/documentation/swiftui/state では、このリアルタイムに更新される値をViewの外部からアクセスするにはどうすればよいか?今回は@Stateと同じProperty Wrapperである@ObservedObjectを用いて、Viewの外部からアクセスしてみようと思います。 はじめに 今回は、ドラッグ可能なオブジェクト(DraggableCircle)の位置をリアルタイムに親View(ContentView)からアクセスするシナリオを考えてみます。 ドラッグ可能なオブジェクトの詳細は以下を参考にしてみてください。 Model定義 今回はMVVMアーキテクチャを意識して作成していきます。 最初にデータモデルを定義します。CGPointを使いたいためSwiftUIをImportしています。 Circleオブジェクトに関連する、ID、名前、位置情報(CGPoint)の3つを定義します。 ModelView定義 次にModelViewを定義します。 このCircleViewModel自体をObservableObjectとし、@Published属性をつけた変数として、先程定義したModelを用います。Initializerが必要なので、ここでデータの初期値を設定します。このClass内にprivate funcを作ることで様々な処理が可能ですが、今回は簡潔さを重視し、Initializerのみとします。 View定義 ここでは、Parent View(CircleView)とChild View(DraggableCircle)の2つを定義します。最初にChid Viewから定義します。 Child View(DraggableCircle) このコードをPreviewすると以下のようになります。viewModelで初期化した名前”circle1″が、同じく初期化した座標上に表示されます。このCircleオブジェクトをLive Previewでドラッグすると、ドラッグに応じて、座標の表示が変わることが分かると思います。 解説 まず、6行目でViewModelで定義したObservableObjectであるCircleViewModel()をObservedObjectとして定義しています。このプロパティviewModelはこのView(DraggableCircle)が呼び出されると、CircleViewModelオブジェクトが生成され、Initializerによって、初期である名前と座標の情報を持ち、DraggableCircle内で参照することができます。 これだけであれば、@Stateを用いて同様のことが実現できます。それでは、次に本題である、この名前や座標をParent View側からアクセスしてみます。 Parent View(Circle View) このViewをPreviewすると以下のようになります。Child Viewでの座標がリアルタイムに表示されつつ、Parent Viewで定義したList内にも同じ値がリアルタイムに表示されていることがわかると思います。 解説 Parent ViewであるCircleViewもChild View同様にviewModelを@ObservedObjectとして宣言します。あとは、Child View同様にアクセスすることでParent Viewでもこの値にアクセスすることができました。また、Child ViewのDraggableCircleをCallする際には、このviewModelを引数に指定します。 ContentView 最後にContentViewを紹介します。CircleViewをCallする際には、新規に作成するCircleViewModelを引数にしていることに注意してください。 まとめ @ObservedObjectは、View内でのアクセスに限られている@Stateに比べ多少使い方のお作法が必要ですが、子から親へ情報を伝達することができるため、その分使えるシーンは増えそうです。大元の親でObservedObjectを作成し、その参照を渡していくことで複数のViewからこのObservedObjectにアクセスできるというかたちになります。Model, ViewModel, Viewそれぞれの役割と、概念的なコミュニケーション図を以下に作成しました。 Property Wrapperには他にも@EnvironmentObjectもあります。今回のケースであれば@EnvironmentObjectでも実装できるはずですが、ObservedObjectの数を動的に増やす場合などは@ObservedObjectの方が向いていそうです。 References

[Python][Selenium]How to launch WebDriver with Headless Chrome

If you are going to use Selenium against a dynamic web site such as using Javascript, you should use Headless Chrome. However, it seems that there are no helpful instruction so far. So I’m going to explain how to launch WebDriver with Headless Chrome. Photo by Diego Molina (diemol) / CC BY-SA 4.0 Environment Mac OS Big Sur 11.1Python 3.8.3ChromeDriver 89.0.4389.23 ChromeDriver Official Sample Code I found the official sample code from ChromeDriver Official Site, however, there are no explanation about “Headless”. Here is the sample code cited from this site. Add options parameters What we have to do to launch with Headless Chrome is to add “options” parameters as following. Note … Read more

[Vue.js]ドロップダウン(b-form-select)の表示内容を動的にフィルタリングしつつ、同時にテーブル(b-table)のアイテムをフィルタリングする方法

以前投稿した、「BootstrapVueのテーブル(b-table)で複数条件によるフィルタを実装する方法」では、複数の条件に従ってテーブルアイテムの内容がフィルタリングされるようにしましたが、今回は、条件として複数のドロップダウン(b-form-select)を使うだけでなく、1つ目のドロップダウンの内容に応じて2つ目のドロップダウンの内容を動的にフィルタリングしながら、同時にテーブルアイテムをフィルタリングする方法を説明します。 使うデータと基本のテーブル 今回は、2019年から2022年までに開催された、もしくはされる予定のサッカーの国際大会決勝をドロップダウンで年、月を絞り込みながら表示アイテムを絞り込んでいく、というシナリオを考えます。使用するデータは以下の通りです。 ドロップダウン(b-form-select)の設置 まずは、絞り込み用のドロップダウンを設置していきます。今回は、年、月の2つのドロップダウンを設置していきます。 データプロパティには、ドロップダウンで選択した値を保持するyearと、ドロップダウンに表示するリストを保持するyear_listを用意します。月も同様です。 ドロップダウンに表示するリストを作成します。 年、月共にリストに値が入りましたが、重複データもありますし、ソートもされていませんので、重複を排除し、ソートすることにします。 重複排除、ソート 重複の排除には以下のようなアロー関数を使うことにします。 重複が排除され、ドロップダウンがすっきりしました。次に、ソートをすることにします。 これで、検索用のドロップダウンの設置が完了しました。この状態では、ドロップダウンを選択しても特に何もおこりません。次に、本題である、ドロップダウンの内容を動的にフィルタリングするようにしてみます。 年(Year)の内容で、月(Month)のリスト項目を絞り込み ここでは、例えばYearドロップダウンで2021を選択した際に、Monthドロップダウンとして、1, 2, 7のみが表示されるように、Year, Monthの順でNarrow Downするようにしてみます。今回はwatchプロパティを使う方法で実装してみます。 ドロップダウンの値が変更されると、このfunctionが呼び出され、選択した値がnewValとして連携されますので、まずはmonthドロップダウンのリストに表示するプロパティのmonth_listを初期化し、データの中から選択されたyearのものだけをmonth_listに格納し、monthドロップダウンに表示するようにしています。このコードを追加すると、以下のような振る舞いになります。 これで、1つ目のドロップダウンの値に2つ目のドロップダウンの値が連動し、動的にドロップダウンの表示項目が変化するようになりました。最後に、この2つのドロップダウンの値に、テーブルアイテムを連動させてみます。 テーブル(b-table)をドロップダウン(b-form-select)の内容でフィルタリング 以下の投稿で説明した方法を、ほぼそのまま流用することで、ドロップダウンの値とテーブルを連動させてみます。細かい部分は、以下の投稿を参考にしてみてください。 上記を実装した結果は以下の通りです。テーブルアイテムが絞り込めて表示できていることが分かると思います。 まとめ 2022年を選択した際に一度テーブルが消えてしまう、一度値を選択すると全検索(当該項目でのフィルタリングなし)ができない、など実用上はもう少しブラッシュアップが必要かと思いますが、冗長になってしまうので、今回はここまでとします。 最終型のソースコード 余談ですが、wikipediaを参考に今回のサンプルデータを作成しましたが、2020年のイベントが軒並み2021年に延期されていることを再認識せざるを得ませんでした…

[Vue.js]BootstrapVueのテーブル(b-table)で複数条件によるフィルタを実装する方法

BootstrapVueのテーブルコンポーネントの<b-table>を使うと、簡単にきれいなテーブルが作成できます。この作成したテーブルを条件によって絞り込んで表示しようと思います。b-tableには、Built-inでフィルタ機能が実装されており、これも簡単にテーブルデータをフィルタリングすることができるのですが、単純にこのフィルタ機能を使うだけでは、列を指定してのフィルタや、複数条件を絡めたフィルタリングを実現することができません。今回は、2つの条件を絡めたフィルタリングでデータを絞り込む方法を説明します。 参考;公式Docs:BootsatrapVue Filtering 使うデータと基本のテーブル 公式サイトにあるものと同じサンプルデータを使います。name, first_name, last_nameの3つの列からなる4つのレコードです。 起動時に、mounted()でデータをテーブル表示用のコンポーネントプロパティであるitemsに読み込んで表示するだけのコードです。 Built-inフィルタ(全列対象) 次に、Built-inフィルタについて説明します。Built-inフィルタは、b-tableのプロパティに検索用の文字列を指定するだけで有効になります。ここでは、入力用のb-form-inputを使って動的にテーブルの内容をフィルタリングしていきます。 数字”8″を入力すると、8を含む行のみが表示されます。今回のデータはAge列のみ数字が入っていますので、89, 38の2行が表示されます。文字列”l”や”m”を入力すると、それぞれの文字が含まれる行のみが表示されます。今回のデータはAge列以外に文字列が入っていますので、実施的にはAge列以外の2列を対象としてフィルタリングされます。 Built-inフィルタ(特定列対象) 上述の通り、ほんの2〜3行追記するだけでフィルタリングが実装できます。ただし、実際の使用場面を考えれば、絞り込みたい列を指定することも一般的かと思います。そこで、次に特定の列でフィルタリングをする方法を説明します。 特定の1列を対象にフィルタリング それでは、first_name列のみを対象にフィルタリングを実装してみます。これは、:filter-included-fieldsプロパティを1つ追加することで実現できます。 参考:Built in filtering options 先程と同じ条件を入力した結果は以下のとおりです。数字を入れると、結果がゼロ件になり、”l”, “m”も、先程はLast Nameの方で検索にひっかかっていたレコードが表示されなくなっていることがわかります。 特定の2列を対象にフィルタリング 次に、first_nameに、last_nameをフィルタリング対象として加える場合を説明します。これは、:filter-included-fieldsの配列パラメータにlast_nameを追加するだけで実現可能です。 これも、同じように、数字(8)、文字列(“l”, “m”)で見ていきます。Age列は引き続きフィルタリング対象外なので、数字を入れても何も表示されないところは変わっていませんが、文字列を入力すると、一番最初の全列対象のフィルタリングと同じ結果に変わってきているため、First Name, Last Nameの2列がフィルタリング対象になっていることがわかります。 なお、同じフィルタリングを:filter-ignored-fieldsを使って、以下の用に記載することもできます。上のコードと下のコードの振る舞いは同じになります。 Custom Filter ここまで、1つのフィルタリング条件を入力し、1つ、または複数列に対してフィルタリングする例をみてきました。これらのようなシンプルなフィルタリングはBuilt-inフィルタリングで簡単に実装できることがわかりました。ところが、複数条件を使ったフィルタリングなど、少し複雑なフィルタリングを実装しようとすると、Built-inフィルタリングでは実現することができません。そこで必要になるのが、Custom Filterです。 参考:Custom filter function Custom Filterの基本 まずは、Custom Filterを使って、Built-inフィルタリングと同等のフィルタリングを実装してみます。公式ドキュメントによると、Custom Filterは:filter-functionプロパティを使って、method内の関数を呼び出すことができ、その際に以下の2つの引数を渡す、ということです。 オリジナルアイテム行レコードデータオブジェクト(the original item row record data object) フィルタープロパティの内容(文字列、正規表現、配列、オブジェクト) 上記に従って、tableFilterというフィルタリング用の関数を作成し、それを:filter-functionで指定することにします。 単一条件でのフィルタ tableFilterでは、まず確認のために、何が渡されているかを出力しています。実質的な処理は最後の行のみで、検索用に入力した値が、テーブルの行単位で渡されるデータのなかに含まれていればtrueを、そうでなければfalseを返す、ということをしています。このコードで同じ用に数字の8を入力してみます。 出力したログを確認してみます。1行ずつ、tableFilterに引数rowとしてデータが渡されていることがわかります。また、検索用に入力した数字はstringとして扱われていますが、rowとして渡されたageのデータはnumberとなっていることがわかります。この値を比較する際は型を合わせるなどひと手間必要そうです。 次に、文字列”l”を入力してみます。2行目の”Larsen”がFirst Nameとして”l”を含んでいるため表示されてほしいところですが、表示されません。 出力したログをみてみます。filterpropとして渡されているのは小文字の”l”で、row.first_nameに含まれているのは大文字の”L”のため、不一致になっています。Built-inフィルタリングではこのあたり”よしな”に処理してくれていますので、Custom Filteringの場合は要注意ですね。 大文字小文字の区別なくフィルタリングするようにコードを修正します。(Cosole.log部分は削除しています) 修正後のフィルタリングは以下のようになります。無事小文字の”l”でも”Larsen”が表示されるようになりました。大文字”A”を入力しても、小文字の”a”を含むデータが表示されています。 複数列を対象としたフィルタ 次に、Built-inフィルタリングの:filter-included-fieldsと同様、フィルタリング対象列を複数にする場合をみていきます。先程同様、filterpropに渡された検索文字列が、rowで渡される各行のデータの、first_name, last_nameそれぞれに含まれているかをチェックし、いずれかに含まれていればtrueを返すようにtableFilterを変更します。 以下の用に、Age列にはフィルタリングが効いていないままである一方、”l”を入力することで、先程は表示されなかったLast Nameに”l/L”が含まれるデータが表示されるようになりました。 複数条件でのフィルタ ここまででCustom FilterでBuilt-inフィルタリング同等の機能を実装することができるようになりました。ここからがやっと本題となる、複数条件でのフィルタリングを実装していきます。ここでは、以下を実現しようとします。 年齢、名前の2つの検索条件を入力 年齢、名前共に、空欄であれば全件表示とする(空欄データがないため表示しない、ということにはしない) 年齢:入力された値がAge列に含む場合、表示する 名前:入力された値が、First Name列, またはLast Name列に含まれる場合、表示する 年齢と名前はAND条件とする(例:「年齢に”8″を含み、かつ名前に”g”を含む」=> 3行目、89歳 Geneva Wilsonを表示 最初に、複数条件を入力できるようにフォームを追加し、それぞれの値を保持するためのプロパティを用意します。 検索条件が2つ(age, name)になった状態です。v-modelのageもnameは何もフィルタリング機能と関連していないため、これらに入力しても何もフィルタリングされません。 ここで、ageまたはnameプロパティが変更されたことをトリガーにフィルタリングさせることを考えます。computedプロパティを使ってこれを実現してみます。先程まで使っていたデータプロパティのsearch_textの代わりに、computedプロパティのfilterを用意します。これは、単純にデータプロパティのage, nameを配列で返す、というものです。 次に、b-table側で:filterプロパティも同様にデータプロパティのsearch_textの代わりに、作成したcomputedプロパティのfilterを指定します。 これで準備完了といきたいところですが、このままだと以下のエラーが出てしまいます。原因は初回、age, nameのいずれかがnullの状態でtoLowerCaseを呼んでいるためです。このエラーへの対応と、要件通り、Ageも対象としたロジックをtableFilterに実装します。 今回は、前回使用した引数で渡されてくるpropfilterの値を使うのではなく、データプロパティの値との比較でロジックを組んでいます。実行結果は以下のとおりです。ageだけ、age+name, nameだけ、いずれでも期待した結果が表示されることがわかります。 まとめ 利用シーンはそれなりにありそうながら、中々わかりやすいサンプルが見つけられなかったため、自分自身の整理の意味も込めて投稿しました。BootstrapVueの公式ドキュメントにすべて記載があるといえばありますが、実例が乏しく苦労しましたが、一度わかってしまえばとても分かりやすい仕組みなので、何かの参考にしていただければ幸いです。 最終型のソースコード References