ここのところ寒いですね。GWも明日からは雨が続くようです。こんにちは。
今回はPart5のサブページ5番目です。
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page
こっからは同じようなものがつづくようなのでまとめてやってしまうかも?です。
bookページのリスト表示
ここでは本のリストと著者のリストを表示させればよさそうです。
mongoDBのBooksをみると著者は当然別のテーブルのidが書かれています。
なのでbooksのリストの各要素のauthor.idをauthorテーブルから置き換えればOKですね。
bookControllerのbook_list
前回と同じように関数を作ってpugファイルを作成します。
exports.book_list = function(req, res, next){
Book.find({}, "title author").populate("author").exec(function(err, list_books){
if(err){return next(err);}
res.render("book_list", {title: "Book List", book_list: list_books});
});
};
ここでまたちょっとわからないところがあります。
findは検索だと思いますが第一引数はフィルターだったかと思います。
第二引数の"title author"とは?
ちょっとmongooseのModel.find()をみてみます
https://mongoosejs.com/docs/api.html#model_Model.find
Model.find(conditions<object>, projection<object|string>, options<object>, callback<function>)
だそうです。
・conditions
{}にフィルタをいれるようです。{name: "john"}など
・projection
そうか、selectっぽいですね。sqlでいうところのSELECT title, athour FROM books
ってことですね!
・option
条件みたいです。
・callback
ここはfunctionを入れるようですが、まだピンときません。。
populate
うーん。。これはまたわからない!
とりあえずドキュメントを張ります。
https://mongoosejs.com/docs/populate.html
説明によると他のコレクションを参照できる代替手段になると。
例をみるとモデルのスキーマに設定されているようなのでbookのmodelをみてみます。
author: {type: Schema.Types.ObjectId, ref: "Author", required: true}
ここのrefというのがそれっぽいです。
設定するのは文字列なのでここと一致させているということだと思います。
models/author.js
//一番最後のマッピング部分
module.exports = mongoose.model("Author", AuthorSchema);
var AuthorSchema = new Schema(
{
first_name: {type: String, required: true, max: 100},
family_name: {type: String, required: true, max: 100},
date_of_birth: {type: Date, default: Date.now},
date_of_death: {type: Date, default: Date.now},
}
);
authorの定義がこれなので、books.author.first_nameとかも可能なのかな?と思います。
execの中のfunctionこれもよくわからない。。
res.render
何はともあれfunctionの第2引数のlist_booksにbookのモデルとそれに付随したauthorのモデルが入っているとします。
はいっているのでしょう。
だとしたらbook_list.pugで使えるアトリビュートは
book.title
book.summary
book.isbn
book.genre
book.url
< 関数
book.author.first_name
book.author.family_name
book.author.date_of_birth
book.author.date_of_death
になります。
genreもリファレンスされていますがこれはどういう扱いでしょう。2つとも欲しい場合は?
一応2つ繋げて書くこともできるようです。
Book.find({}, "title author").populate("author").populate("genre").exec(function(err, list_books))
pugにbook.genreといれたらオブジェクトが表示されました。
が、欲しい感じでは受け取れていません。authorと比べてgenreは配列だから?という気もしますが
そちらはおいおい見ていけたらと思います。
book_list.pug
さて今度はこれをレンダリングするためのpugファイルを作成します。
extends layout
block content
h1= title
ul
each book in book_list
li
a(href=book.url) #{book.title}
| (#{book.author.name})
else
li There are no books.
上部は定型文でlayoutを継承してblockのcontentを置き換えますよという記述。
今回はfor 分が入っています。each文っていうんですかね。
#{}は#{アトリビュート(virtual関数?)}という用途もあるようです。
さてPart5はこの後12まで続きますが大体ここまで書いたことの繰り返しなので
割愛します!
だんだんページができてくるのは嬉しいものです。
つづく