今回は、railsコンソールでDBのデータを取得し確認する方法を学んだので記載致します!
まぁ、モデルにデータを突っ込んだ後にデバックして確認出来るので、かなりためにならない記事なるかもしれませんがご勘弁してください(T . T)
モデルのプロパティとDBのデータ内容
今回使用するモデルとデータは下記になります。
class User < ApplicationRecord
has_many :comment
end
#Userクラスのプロパティ
t.string :user_name
t.integer :age
class Comment < ApplicationRecord
belongs_to :user
#Commentクラスのプロパティ
t.string :text
usersテーブル
user_name | age |
---|---|
山田 | 18 |
鈴木 | 20 |
田中 | 21 |
commentsテーブル
user_id | text |
---|---|
1 | 山田コメント1 |
1 | 山田コメント2 |
2 | 鈴木コメント |
(データが適当で申し訳ない)
ここからコンソール上での操作になります
1つのレコードのみ取得
###userテーブルから山田のレコードを取得
user = User.find(1)
###SQLの実行クエリ
SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
###取得したレコード内容
<id: 1, user_name: "山田", age: 18, created_at: nil, updated_at: nil>
###取得したレコードの年齢のみ表示
user.name
18
上記のような操作は、一度は実行したことがあると思います。
内容としては、DBから「usersテーブルのidが1のレコードを取ってきて」と命令してインスタンス変数に格納しています。
この変数userには、ハッシュの形でデータが格納されています。
なので、このデータの年齢だけ取り出したい場合は、「user.age」と入力すれば
keyになっているagyのバリューである18のみ取得できます。
複数レコードの取得
###userテーブル全てを取得
user = User.all
###SQLの実行クエリ
SELECT `users`.* FROM `users`
###取得したレコード内容
[#<User:0x00007f8cbb348bf0 id: 1, user_name: "山田", age: 18, created_at: nil, updated_at: nil>,
#<User:0x00007f8cbb348b28 id: 2, user_name: "鈴木", age: 20, created_at: nil, updated_at: nil>,
#<User:0x00007f8cbb348a60 id: 3, user_name: "田中", age: 21, created_at: nil, updated_at: nil>]
複数のレコードを取得すると多分上記のような形になると思います。
複数レコードのデータを取得した場合、単一レコードを取得した時とデータの形が変わります。
単一のレコード場合はデータの形はハッシュでしたが、複数のレコードの場合は、データの形が配列になります。
配列の中に1レコードづつ入っているイメージだと考えやすいかもしれません。
では、変数userの中に入っている山田さんのレコードのみ表示させる場合と
山田さんの年齢のみ表示させる方法は下記になります。
###山田さんのレコードのみ表示
user[0]
id: 1, user_name: "hajime", age: 18, created_at: nil, updated_at: nil>
###山田さんの年齢のみ表示
user[0].age
18
山田さんの年齢のみ表示させたい場合は、まず変数userに格納されている配列の0番目を
指定します。
0番目の配列には、山田さんのレコードがハッシュの形で格納されていますので、
データを表示させる場合は「user[0].age」
注意)
DBのレコードにはidで自動採番されている番号がありますが、DBのidには、自動採番の0番目というのは存在しません。
しかし、rubyに限らず配列のプログラムは0番目から始まります。
複数のテーブルから紐付くデータを取得
###userテーブル全てを取得
user = User.all.includes(:comment)
###SQLの実行クエリ
SELECT `users`.* FROM `users`
SELECT `comments`.* FROM `comments` WHERE `comments`.`user_id` IN (1, 2, 3)
###取得したレコード内容
[#<User:0x00007f8cbb348bf0 id: 1, user_name: "山田", age: 18, created_at: nil, updated_at: nil>,
#<User:0x00007f8cbb348b28 id: 2, user_name: "鈴木", age: 20, created_at: nil, updated_at: nil>,
#<User:0x00007f8cbb348a60 id: 3, user_name: "田中", age: 21, created_at: nil, updated_at: nil>]
上記は、usersテーブルのユーザに紐付くcommentテーブルのレコードを一緒に
取得し、変数userに格納しています。
今までと違いSQLの実行クエリが2つになっています。
注)ここからは、自分のでき悪さにずっと悩んで嫌悪した箇所です(( _ _ ))
では、今回取得したレコードの中から鈴木さんがコメントしたレコードを表示させます。
注)かなり上方になりますがDBのデータを元に記載しています。
###鈴木さんのコメントしたレコードのみを表示
user[1].comment[0].text
鈴木コメント
###山田さんのコメントしたレコードかつ、2つ目のコメントのみを表示
uset[0].comment[1].text
山田コメント2
まず、鈴木さんコメントを表示させる方から説明します。
usersテーブルから複数レコードを取得するとろまでは前回と一緒になりますが、
今回は、usersテーブルのユーザに紐づいたコメントも一緒に取得しているため、
user.all.includes(:comment)でcommentテーブルからも
紐付くレコード取得しています。
ざっくりですが、
このクエリでusersテーブルから全てのレコード取得
SELECT users
.* FROM users
usersテーブルから取得したレコードのidが1,2,3に紐付くレコードのみを取得
SELECT comments
.* FROM comments
WHERE comments
.user_id
IN (1, 2, 3)
紐付くレコードは、1件であっても全て配列の形で変数に格納されています。
なので、変数userから鈴木さんのコメントのみを表示させたい場合は、
user配列の1番目の要素の中にさらに配列があり、その配列のハッシュキーtextにアクセスすると
無事に「鈴木コメント」が表示されます。
user[1].comment[0]
図で表すとこんな感じです。
まとめ!!
はぁ😩モヤモヤがやっと解決したが別にこれができたからといって何かメリットが有るのか?と
言われるとないのではないかと思う。
何故ならコントローラで変数をデバッグすれば中身が見れるので、わざわざコンソールでする必要もないかと思った(T . T)
余談だが、今回userに紐付くレコードなのでuserが1に対してcommentが複数なのでN
N+1問題がなんとなくわかりました。
実はuserに紐付くcommentのレコードは、includesしなくても表示できます。
何故ならマイグレーションファイルでテーブル結合の設定してますからね!
ただし、commentテーブルのレコード取得するたびに、SQLのクエリがは発生するため、パフォーマンスが出ません。
当然ですよね。笑
ユーザ毎にコメントを取得するたびにクエリが走るわけですから。なので、最初からincludesで紐付くレコード全て
取得しておけば最初だけクエリが実行され毎回実行しなくてすみます。
下記はおまけ記事です。
includesしないパターン
###全てのusersテーブルのレコード取得
user = User.all ###変数userに格納
###SQLの実行クエリ
SELECT `users`.* FROM `users`
###取得結果
[ id: 1, user_name: "山田", age: 18, created_at: nil, updated_at: nil>,
id: 2, user_name: "鈴木", age: 20, created_at: nil, updated_at: nil>,
id: 3, user_name: "田中", age: 21, created_at: nil, updated_at: nil>]
###山田コメントを取得
user[0].comment[0] ###変数userの配列0番目の中の配列0番目ユーザコメントを呼び出し
user[0].comment[1] ###変数userの配列0番目の中の配列1番目ユーザコメントを呼び出し
###SQLの実行クエリ
SELECT `coments`.* FROM `coments` WHERE `coments`.`user_id` = 1
[ id: 1, text: "山田コメント1", user_id: 1, created_at: nil, updated_at: nil>,
id: 2, text: "山田コメント2", user_id: 1, created_at: nil, updated_at: nil> ]
###鈴木コメントを取得
user[1].comment[0] ###変数userの配列0番目の中の配列0番目ユーザコメントを呼び出し
###SQLの実行クエリ
SELECT `coments`.* FROM `coments` WHERE `coments`.`user_id` = 2
[ id: 1, text: "鈴木コメント", user_id: 2, created_at: nil, updated_at: nil>]
ユーザ毎にクエリが発生。
includesするパターン
###全てのusersテーブルのレコード取得し、さらに紐付くcommentテーブルのレコード取得
user = User.all.includes(:coment)
###SQLの実行クエリ
SELECT `users`.* FROM `users`
SELECT `coments`.* FROM `coments` WHERE `coments`.`user_id` IN (1, 2, 3)
[id: 1, user_name: "hajime", age: 18, created_at: nil, updated_at: nil>,
id: 2, user_name: "yuta", age: 20, created_at: nil, updated_at: nil>,
id: 3, user_name: "kazune", age: 22, created_at: nil, updated_at: nil>]
###山田コメントを取得
user[0].comment[0] ###変数userの配列0番目の中の配列0番目ユーザコメントを呼び出し
###鈴木コメントを取得
user[1].comment[0] ###変数userの配列0番目の中の配列0番目ユーザコメントを呼び出し
SQLのクエリは発生しない。
ユーザ毎にクエリは発生しない。