Mongooseドキュメントのserialize/deserialize

Mongooseを利用している場合、読み込んだドキュメントをserialize/deserializeしたい場合があると思います。
serializeは雑にtoJSON、でいいと思うのですがdeserializeはどうするのか?

一つのやり方として、hydrateメソッドを使用するやり方があります。

const user = await User({
  name: 'name',
  password: 'password',
  createdAt: new Date(),
  updatedAt: new Date()
});
await user.save();

// JSONからUserドキュメントに戻す
const jsonOfUser = await user.toJSON();
const hydratedUser = User.hydrate(jsonOfUser);

console.log(hydratedUser); // User { name: ... }

ここで気になるのがhydrateした場合は、永続化済みかどうかのコンテキストがわかるのかという疑問があります。
通常はドキュメントのisNewプロパティ調べられますが、hydrateした場合はどうかということです。

検証してみる

試してみた結果はisNewプロパティがfalseになっていることがわかりました。

const user = await User({
  name: 'name',
  password: 'password',
  createdAt: new Date(),
  updatedAt: new Date()
});
console.log(user.isNew); // まだ永続化していないので、true
await user.save();
console.log(user.isNew); // 永続化したのでfalse

const jsonOfUser = await user.toJSON();
const hydratedUser = User.hydrate(jsonOfUser);

console.log(hydratedUser.isNew); // falseが返ってくるが根拠はなんだろうか?

しかし、isNewがfalseになる根拠はなんでしょうか?
これはMongooseのソースを読まないとわからないのでみてみます。(バージョンはv5.8.9)

// model.js
Model.hydrate = function(obj) {
  _checkContext(this, 'hydrate');

  const model = require('./queryhelpers').createModel(this, obj);
  model.init(obj);
  return model;
};

queryhelpersを読み込み、createModelを実行してモデルを初期化しているようです。
引数にisNewオプションを指定していますね。
なので、hydrateでドキュメントに戻した場合は強制的にisNewがfalseになります。

// queryhelpers.js
return new model(undefined, fields, {
  skipId: true,
  isNew: false,
  willInit: true
});

当たり前といえば当たり前ですね。
てっきりhydrateを使用する際の引数のオブジェクトにObjectIdが指定されていれば、永続化済みの状態にするのかと思っていたのですが そんなことはなかったです。

netlifyのNodejsのバージョン

netlifyを利用していて、デプロイ時のNodejsのバージョンを指定したいので調べてみました。
ドキュメントでは下記のやり方があるようです。

docs.netlify.com

  1. 環境変数のNODE_VERSIONで指定する。
  2. .node-version または .nvmrcをリポジトリのルートに置く。

環境変数はバージョンを切り変える際に変更するのが面倒なので使用しないことにしました。
なので.node-versionを置くことにしました。

というのも、自分は普段ローカルではnodenvを使用しているので、.node-verisonを置くだけでバージョンの切り替えができて都合がよかったからです。

バージョンあげるのも.node-verisonを書き換えるだけで済みますし、非常に楽ができます。

2019年の靴の着用回数を集計した

2018年から引き続き履いているもの、買い足したもの、手放したものを集計対象にしています。
昨年の末くらいから集計できるように年間のレポートを表示できる仕組みを365shoesに追加していました。

2019年は520件を投稿していたようです。
一つの靴について、だいたい年間で15回ぐらいの着用、サンダルのみ使用頻度が高いので、倍ぐらいの着用回数になっています。

靴は1年間で10足増えて、5足手放し、合計で28足になりました。

集計のレポートはまたちょっと変える予定です。

2018年から引き続き履いているもの

No. ブランド モデル 2019年までの着用回数 2019年の着用回数
1 Tokyo Sandals DOBULE MONK SANDAL 90 59
2 Rolling dub trio ROOTS 33 29
3 Chippewa Suburban 19 16
4 Pistorelo Norwogian Split 23 16
5 Berwick Chukka boots 27 17
6 Redwing Irish Setter 29 19
7 Redwing Irish Setter 30 19
8 SLOW WEAR LION OB-8208G オイルドレザーサイドゴアブーツ 29 18
9 SLOW WEAR LION OB-8593GT 栃木レザープレーンミッドブーツ 28 17
10 SLOW WEAR LION OB-8593G オイルドレザープレーンMIDブーツ 26 16
11 Chippewa Bridgeman 25 16
12 Chippewa Bridgeman 26 17
13 Chippewa 6inch Service Boots 29 18
14 Chippewa 6inch Service Boots 28 17
15 BROTHER BRIDGE McCLOUD 29 17
16 BROTHER BRIDGE JAMES 29 20
17 Hunter Chelsea Boots 30 15
18 Nicks 6inch HotShot 29 18

買い足したもの

オーダーしたWescoが届いたり、サンダルをオーダーしたり、Redwingのブーツ買ったり色々ありました。
イギリスの靴が増えましたね。

No. ブランド モデル 2019年までの着用回数 2019年の着用回数
1 Berwick Chukka boots 2 2
2 Crockett&Jones CONISTON 5 5
3 BROTHER BRIDGE Morgan 5 5
4 Redwing 1930s Sport Boot 7 7
5 Scotch Grain Spider 9 9
6 Wesco Custom Jobmaster 8 8
7 Sanders Military Apron Derby Boots 11 11
8 Berwick Wing tip 16 16
9 Tokyo Sandals Enginier Slip on 35 35
10 RAMSEY 442 MILITARY CAP TOE OXFORD 31 31

手放したもの

昨年は住んでいる上の階で水漏れがあり、リビングで水が垂れ始めたので対応する場所を確保するため泣く泣く手放しました。
おかげで、ブーツフェスティバルにいけませんでした。

No. ブランド モデル 2019年までの着用回数 2019年の着用回数
1 Timberland Earthkeepers 6inch Boots 12 5
2 Timberland 3eye Classic Lug 7 2
3 Timberland 3eye Classic Lug 12 5
4 Hunter Original festival chelsea boots 22 9
5 Timberland 6inch Premium Boots 11 5

OCamlのパッケージインストール時にファイルをコピーする

OCamlプログラムをduneを使用してビルドしている場合、インストールする時にバイナリファイル以外のファイルも一緒にコピーしたい場合があると思います。

それをopam、duneを使用している時にどのように行うか調べました。

Duneの設定

設定はduneファイルにStanzaの設定を追加するだけです。 dune.readthedocs.io

filesにコピーしたいファイル、sectionにコピー先、packageにパッケージ名を指定します。
パッケージ管理にopamを利用している場合は、/[ホームディレクトリ]/.opam/[コンパイラバージョン]/[Sectionで指定したカテゴリ]/[パッケージ名] にファイルがコピーされます。

具体的には /Users/holyshared/.opam/4.09.0/share/ogenになります。

(install
  (files ../templates/opam.mustache ../templates/default.mk)
  (section share)
  (package my_package)
)

大抵の場合はexecutable, executables stanzaのいずれかと一緒に指定する事になると思います。

(executables
  (names main)
  (public_names ogen)
  (libraries ogen cmdliner)
)

(install
  (files ../templates/opam.mustache ../templates/default.mk)
  (section share)
  (package my_package)
)

プログラムからのファイルの参照

インストール時にコピーしたファイルを読み込んだりしたい時、opamの場合はパスを環境変数のOPAM_SWITCH_PREFIXを利用して解決します。

OPAM_SWITCH_PREFIX/[ホームディレクトリ]/.opam/[コンパイラバージョン]/ になります。
これはopamでコンパイラのバージョン切り替えたりしても正しく切り替わります。

この環境変数は /[ホームディレクトリ]/.opam/opam-init/variables.sh に定義されています。
後はプログラムで Sys.getenv_opt などを利用してパスを取得します。

let prefix = match Sys.getenv_opt "OPAM_SWITCH_PREFIX" with
  | Some v -> v
  | None -> ""

パッケージのインストール

パッケージのインストールはビルドした後に、installコマンドを実行することでローカルにインストールできます。

dune build
dune install

テスト容易性設計のやつOCamlでやってみた

自分の場合は現在時刻を引数で渡すようにしました。
モジュールやコンテキスを表すデータ型みたいなものを渡してもいいんですが仰々しいので。

t-wada.hatenablog.jp

コードはここに置いてあります。
Design-for-testability - OCaml version · GitHub

実装として、ファンクタに表示するメッセージのリストを渡して、挨拶用のモジュールを定義できるようにしてあります。
モジュールは下記の4つのモジュールです。

  • Time - 時刻を扱うデータ型モジュール
  • Time_range - 時刻の範囲を扱うデータ型モジュール
  • Greeter_message - 挨拶のデータ型モジュール
  • Greeter - 時刻によって挨拶を返すモジュール
open Greeter

module Greeter = Greeter.Make(struct
  (* 05:00:00以上 12:00:00未満 *)
  let morning = Time_range.create
    ~stime:(Time.create ~hour:5 ~min:0 ~sec:0)
    ~etime:(Time.create ~hour:12 ~min:0 ~sec:0)

  (* 12:00:00以上 18:00:00未満 *)
  let noon = Time_range.create
    ~stime:(Time.create ~hour:12 ~min:0 ~sec:0)
    ~etime:(Time.create ~hour:18 ~min:0 ~sec:0)

  (* 18:00:00以上 05:00:00未満 *)
  let night1 = Time_range.create
    ~stime:(Time.create ~hour:18 ~min:0 ~sec:0)
    ~etime:(Time.create ~hour:23 ~min:59 ~sec:60)
  let night2 = Time_range.create
    ~stime:(Time.create ~hour:0 ~min:0 ~sec:0)
    ~etime:(Time.create ~hour:5 ~min:0 ~sec:0)

  let messages = [
    (Greeter_message.create ~range:morning ~msg: "おはようございます");
    (Greeter_message.create ~range:noon ~msg: "こんにちは");
    (Greeter_message.create ~range:night1 ~msg: "こんばんは");
    (Greeter_message.create ~range:night2 ~msg: "こんばんは")
  ]
end)

またテスト用のパッケージをインストールするのが面倒だったので、テストの実行部分のコードを書きました。
通常はounitやppx_inline_testとかを使用した方がいいと思います。

ビルドもduneではなくocamlfind、ocamloptを使用しています。
適当なコード書くときに*.opam、duneファイル書くの結構面倒なんですよね。

感想

OCamlで時刻を扱うコードを書くの今ままでなかったので、標準モジュールを調べたりして、またOCamlに詳しくなりました。

今回はUnixモジュールのlocaltime、time関数やtm型を使用しました。
Windowsでは動かないと思います。

Levi’sのGOOGLE JACQUARD トラッカージャケット買ってみた

Levi’sのGOOGLE JACQUARD トラッカージャケット買ってみた

f:id:holyshared:20191014234502j:plain
Levi’sのトラッカージャケット

10月5日に発売ということだったので、面白そうだし買おうかなと思いWebから購入しました。
Webだと1日早くて、4日から買えたみたいです。

これは米国だと、前に発売されていたみたいで、自分の場合はrebuild.fmで知りました。

rebuild.fm

セットアップ

本当は10月12日に届く予定だったのですが、台風だったので13日に受け取り、その日のうちにセットアップし、実際に着てみました。

セットアップは専用のアプリケーションをインストールして、チュートリアルにそって操作していくだけでできました。
自分の場合は音楽再生が一番わかりやすいかなと思い、ジェスチャーの割り当ては下記のようにしました。

ジェスチャー 操作
下にスワイプ 次の曲
上にスワイプ 前の曲
ダブルタップ 曲の再生・停止

今の所の使用感

f:id:holyshared:20191014235127j:plain
ジャケットの袖口

使用感としてはなかなか良いです。
音楽再生の場合、今まで画面みながら曲を飛ばしながらしてたのですが、スマホみなくていいのは思いの外体験がよかったです。

ただし、袖をサッとやる操作はちゃんと袖口を触ってないと反応してくれない場合があるのか反応が鈍く感じる時がありました。
また、Bluetoothの接続が切れやすい感じがします。
なかなか反応してくれなくて、スマホの画面で接続確認とかする場合が1日のうち2、3回あった気がします。

後カメラ撮影の設定は便利そうでした、撮影タイミングをコントロールきるので複数人で撮りたい場合はいいと思います。

ジャケットとしてはよくできてると思います。
でも自分の場合はLeeの101Jが好きなので、できればそっちで出して欲しかった。

今の所の不満

  1. 開発用のSDKがないぽい。
  2. ジャケットの色のバリエーション増やして欲しい。

特にSDKは欲しいですね。

履いた靴の記録を取っている

昨年の6月くらいから履いた靴の記録を残すようにしました。   365shoes.style

残す理由は以下の通りです。

  • 手持ちの靴が革のものが多く、経年変化の記録を残したい。
    • いつの間にか変わってることが多い。
  • 靴が気付いたら増えているので、増減を記録したい。
    • 学習しないんや。。。
  • 靴のレビューを残したい。
    • 今まで履いてきたものの記録がない為、反省できない場合が多い。
  • 履く頻度の低い靴の処分判断がしたい。
    • あまり履いてないな、という感覚があるがどの程度が不明なことが多い。

開発のスタイル

基本的に土日にコードを書くスタイルです。
軽度のものは、勤務時間の休憩時間で対応しています。

技術スタックは下記のものを使用しています。
そのうちTypeScript、Next.jsに置きかえると思います。

  • Flow
  • Nodejs
  • React
  • Express
  • GraphQL
  • MongoDB
  • Heroku
  • AWS(S3)
  • Cloudflare
  • Cloudinary

2018年の集計結果

ちなみに昨年2018年の集計結果は下記の通りになりました。

Tokyo Sandalsのサンダルは利用頻度が差も高くて、その次にHunterのレインブーツ、後はローテンションで大体履いているので、ほぼ横並びです。

靴、サンダルの数は最終的に23足でした。(こんなにいらないと思う)

ブランド 名前 回数
Nicks Boots 6inch HotShot 11
Hunter Chelsea Boots 15
Hunter Original Festival Chelsea Boots 13
Brother Bridge JAMES 9
Brother Bridge McCLOUD 12
Rolling Dub Trio ROOTS 4
Tokyo Sandals DOBULE MONK SANDAL 31
Chippewa 6inch Service Boots Burgundy 11
Chippewa 6inch Service Boots Crazy house 11
Chippewa Bridgeman Burgundy 9
Chippewa Bridgeman Black Odessa 9
Chippewa Suburban Navy 3
Slow Wear Lion オイルドレザープレーンMIDブーツ Red 10
Slow Wear Lion 栃木レザープレーンミッドブーツ 11
Slow Wear Lion オイルドレザーサイドゴアブーツ 11
Redwing Irish Setter Black 11
Redwing Irish Setter Gold russet 10
Berwick Chukka boots 10
Timeberland 6inch Premium Boots 6
Timeberland 3eye Classic Lug Burgundy 7
Timeberland 3eye Classic Lug Brown 5
Timeberland Earthkeepers 6inch Boots 7
PISTOLERO Norwogian Split 7