LoginSignup
2
0

More than 5 years have passed since last update.

現場のSails.js #5 バッドプラクティス

Posted at

概要

弊社では一部の社内プロジェクトでSails.jsを利用しています。その中で得られたベストプラクティスやらバッドプラクティスをまとめていこうと思います。
第5回はバッドプラクティスについて。

動作環境

node.js v0.12.7
Sails.js v0.11.2
sails-mysql v0.11.0

Sails.jsのバッドプラクティス

node.jsのMVCフレームワークはRailsのようにデファクトが無い状態です。デファクトがない理由はやはり、どのフレームワークも成熟しているとは言いがたい状態でしょう。Sails.jsはその中でも(たぶん人気がないので)微妙な点が多いです。そういった微妙な点と、その解決策についてまとめてみました。

DeepPopulateが出来ない

Sails.js(のO/R MapperであるWaterline)では、SQLで言うところのJOINをするために以下のように記述します。

Article.findOne(1).populate('tags').then(articles => {
  // {id: 1, title: "hoge", tags: [{id: 1, name: "Sails"}]}
});

しかし、populate()は現時点で1段階のJOINのみ(交差テーブルの時は2段階まで)しか対応していません。なので例えばArticleにwriterをJOINして、さらにwriterの所属企業情報をJOINするというQueryが1度で書けないようになっています。

そのため、2つのQueryを投げて自力でJOINする必要があります。

Article.find().populate('writer').then(articles => {
  const IDs = _.map(articles, a => a.writer.company);

  return Company.find(IDs);
}).then(companies => {
  // ここで自力でarticlesにcompaniesを連結
});  

一応、DeepPopulate対応はしばらく前からPullRequestができていて、実装は進んでいるようです。

Model.destroy()の結果がcolumnNameに対応していない

Waterlineは以下のようにDBスキーマとマッピングするときに、tableNamecolumnNameを指定することでSails上で別の名前で扱う事ができます。

/api/models/User.js
module.exports = {
  tableName: 'users',

  attributes: {
    displayName: {
      columnName: 'display_name',
      type: 'string',
      required: true
    }
  }
};

ただし、執筆時点ではModel.destroy()の結果として返ってくるモデルにはこの制約が効かないようです(上記の例だと、keyがdisplay_nameとしてObjectが返ってくる)。まあ普通にdisplay_nameでアクセスしたらいいのですが、気持ち悪さはかなりある。

User.destroy(1).then(user => {
  // => [{id: 1, display_name: 'hoge'}]
});

この問題、以前に似たようなPullRequst(そのときはpopulate内のwhere句でcolumnNameが効かない問題だった)を出したことがあるのでだいたい検討は付くのですが、この場合は完全にBreakingChangeになってしまい面倒で調査していません。。

junctionTableにcreatedAt/updatedAtがない

これが一番困ったところで、createdAt/updatedAtがjunctionTableには付かないようです。例えばAritcle/Userという2つのテーブルが存在し、「ユーザがお気に入りした記事」というものをArticleFavoriteというjunctionTableで表現しようとしたときに、createdAt/updatedAtが保存されません。updatedAtはjunctionTableなので不要ですが、createdAtが無いと例えば「日付ごとのお気に入り数」がMySQLのデータのみだと取れなくなってしまいます。

対策としては、ArticleFavoriteをjunctionTbleではなく普通のModelとして定義することくらいでしょうか。ただsave()が使えなくなるので微妙な所。

ArticleFavorite.create({user: 1, article: 1});

他のO/R Mapperだとどうなんでしょう?

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0