Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@KeitaMoromizato

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

概要

弊社では一部の社内プロジェクトで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だとどうなんでしょう?

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?