「入門Node.jsプログラミング 」の感想・備忘録6

スポンサーリンク
「入門Node.jsプログラミング 」の感想・備忘録5の続き

Lesson17

バリデーションを追加する

models/subscribers.jsのスキーマ定義を修正

  • 型はString, Date, Array, Mixed, ObjectIdなど。
  • lowercase: trueとすると、値が小文字に変換される。
const subscriberSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: {
    type: String,
    required: true,
    lowercase: true,
    unique: true
  },
  zipCode: {
    type: Number,
    min: [10000, "Zip code too short"],
    max: 99999
  },
});
静的メソッドとインスタンスメソッド
  • スキーマには静的メソッド・インスタンスメソッドを定義することができる。
  • 静的メソッド: subscriberSchema.xxx = function() {};
  • インスタンスメソッド: subscriberSchema.methods..xxx = function() {};
    ※ アロー関数にするとメソッド内でthisが使えなくなるのでfunctionで定義
// インスタンスメソッドの定義
subscriberSchema.methods.getInfo = function() {
  return `name=${this.name}, email=${this.email}`;
};

// インスタンスメソッドの呼び出し
Subscriber.findOne({}).exec().then(subscriber => {
  console.log(subscriber.getInfo());
});

アソシエーションを作る

SubscriberモデルにCourseモデルを紐づける場合、models/subscriber.jsのスキーマ定義に追加する。
※ 関連付けは相互に参照する必要はない。片方のモデルがもう片方のモデルを参照するだけで十分。

  • 1対1の場合
    course: { type: mongoose.Schema.Types.ObjectId, ref: "Course" }
  • 1対多の場合
    courses: [{ type: mongoose.Schema.Types.ObjectId, ref: "Course" }]
  • 利用方法
    subscriber1.course = course1;
    配列の場合はsubscriber1.course.push(course1);
"use strict";

const mongoose = require("mongoose");
const courseSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
    unique: true
  },
  description: {
    type: String,
    required: true
  },
});
module.exports = mongoose.model("Course", courseSchema);

関連モデルからデータを記入する

Mongooseのpopulateメソッドを使うと、関連付けられたモデルのデータを取得(クエリ結果に記入)することができる。

Subscriber.findOne().populate('course').then(subscriber => {
  console.log(subscriber.course);
});

// インスタンスを指定する場合
Subscriber.populate(subscriber, 'course').then(subscriber2 => {
  console.log(subscriber2.course);
});

Lesson18

ユーザーモデルを作る

1. models/user.jsの作成

  • nameのfirstとlastのように、オブジェクトを入れ子にすることが可能。
  • スキーマのvirtualメソッドを使って、仮想属性(データベースには保存されない属性)を定義することができる。
    例) firstとlastからフルネームを取得する。
  • timestamps: trueでcreatedAtとupdatedAtが追加される。
"use strict";

const mongoose = require("mongoose");
const {Schema} = mongoose;
const userSchema = new Schema(
  {
    name: {
      first: {
        type: String,
        trim: true
      },
      last: {
        type: String,
        trim: true
      }
    },
    email: {
      type: String,
      required: true,
      lowercase: true,
      unique: true
    },
    zipCode: {
      type: Number,
      min: [1000, "Zip code too short"],
      max: 99999
    },
    password: {
      type: String,
      required: true
    },
    courses: [{type: Schema.Types.ObjectId, ref: "Course"}],
    subscribedAccount: {
      type: Schema.Types.ObjectId,
      ref: "Subscriber"
    }
  },
  {
    timestamps: true
  }
);
userSchema.virtual("fullName").get(function() {
  return `${this.name.first} ${this.name.last}`;
});
module.exports = mongoose.model("User", userSchema);

2. controllers/usersController.jsの作成

  • module.exportsにアクションをオブジェクトとして代入すると、管理しやすくなる。
  • indexアクションとindexViewアクションに分け、データはres.localsを使って引き渡す。
"use strict";

const User = require("../models/user");
const Subscriber = require("../models/subscriber");
module.exports = {
  index: (req, res, next) => {
    User.find({})
      .then(users => {
        console.log(users);
        res.locals.users = users;
        next();
      });
  },
  indexView: (req, res) => {
    res.render("users");
  },
  addUser: (req, res) => {
    let createdUser;
    const newUser = new User({
      name: {
        first: req.body.first,
        last: req.body.last
      },
      email: req.body.email,
      password: req.body.password,
    });
    newUser.save().then(user => {
      createdUser = user;
      return Subscriber.findOne({email: req.body.email});
    }).then(subscriber => {
      createdUser.subscribedAccount = subscriber;
      createdUser.save();
    }).then(() => {
      res.render("thanks");
    });
  }
}

3. index.jsに追加

app.get("/users", usersController.index, usersController.indexView);

コメント