20200809のMySQLに関する記事は4件です。

Node.jsでmysqlのDate型が勝手にDatetime型で取得される問題を解決する

はじめに

Node.jsドドド初心者です。ローカルで動くDBの情報を表示する簡単なアプリを作成しようと思い立って作ったのですが、思わぬところで落とし穴があったので、それについての覚え書きです。
Node.js Expressで、mysqlを操作している際に発生した事象です。

DATE型がDATETIME型として取得されてしまう

今回表示するテーブルは非常にシンプルな情報で構成されていました。

table名 : youtube
+----+------------+-----------------------------------------------------------------+
| id | date       | title                                                           |
+----+------------+-----------------------------------------------------------------+
|  1 | 2020-08-08 | 【絶対解けない】答えが「見たことない字」になる合体漢字クイズ          |
|  2 | 2020-08-07 | 数学の図形を使った共通点当てゲームで爆笑連発!【VENN'S CODE】        |
|  3 | 2020-03-27 | 伊沢vs伊沢vs伊沢vs伊沢                                            |
+----+------------+-----------------------------------------------------------------+

(中身は、すきなYoutuberさんの動画の情報を拝借しました。)

しかし、実際に情報をNode.jsで表示すると、DATE型のdateカラムが勝手にDATETIME型になってしまう問題が発生しました。
コードは以下の通りです。

app.js
/*(中略)*/
app.get("/youtube_list",(req,res) =>{
    connection.query(
      'SELECT * FROM youtube',
      (error,results) =>{
        res.render("youtube_list.ejs",{items: results});
   )};
});
youtube_list.ejs
  <% items.forEach((item) => { %>
    <li>
      <div class="item-data">
         <span class="id-column"><%= item.id %></span>
         <span class="first-column"><%= item.date %></span>
         <span class="second-column"><%= item.title %></span>
      </div>
    </li>
<% }); %>

調べた際に、同様の事象が発生している方が何人かいました。JSONの仕様では?という話もあったので、おそらくその影響でしょうか。

シンプルな解決策:connection option

最初は、関数を作ってDATETIME型の情報をこねくり回す方法を取ったのですが、その後改めて調べてみたら、とても単純な話で、「connectionの際にoptionを付与するだけ」でした。

app.js
const connection = mysql.createConnection({
  host:'localhost',
  user:'root',
  password:'password',
  database:'quizknock',
  dateStrings: 'date' /*または'true'*/
});
connection.connect();

このdateStringsで、mysqlから取得するデータを文字列として取得することができます。
知ってしまえばめちゃくちゃ簡単ですね・・・
参考:mysql Git

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deviseでusersテーブルを作成しようとした時に発生したMysql2::Error:Specified key was too long; max key length is 767 bytesのエラー対処法

基本的には何もいじらずデフォルトの設定でマイグレーションしようとしただけなのでそれでエラー出るってどうよっていう話ですが、gem入れた後に

rails g devise user

でモデル作って何も触らず

rails db:migrate

しようとしたら

Mysql2::Error: Specified key was too long; max key length is 767 bytes

とエラーが出ました。
原因はこちらの記事に実にわかりやすくまとまっていました。
emailの文字数制限を変えることで解決する方法が載っていました。

自分はめっちゃ長いメールアドレスあったらどうすんねんとか訳のわからない意見が自分の中に湧き上がってきたので別の方法で解決しました。ええ。文字コード自体変えました。

database.yml
default: &default
  adapter: mysql2
  # encodingの値をutf8mb4からutf8に変更
  encoding: utf8 
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
  #(以下略)

めでたしめでたし。
それにしてもカラムの型がvarchar(255)だとエラー出るとか納得いかない

参考にした記事

https://qiita.com/terufumi1122/items/9ea764618eba01144e09

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

INSERT を重複せずに実行する

あるテーブルに重複有無を確認後、重複がなれけばINSERTしたいときの方法。

例えば users_booksテーブルが以下のようにあったとします。

id user_id book_id
1 5 10

ここで重複の有無を確認して、同じレコードが入っていないときINSERTしたいなら、以下のSQL文でできました。

INSERT INTO users_books(user_id, book_id) 
SELECT 5, 10, 
WHERE NOT EXISTS (SELECT user_id FROM users_books WHERE user_id = 5 AND book_id = 10)

注意する点として、通常のINSERTなら VALUESとなっているところが、SELECTになっていること。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】summernote 本番環境で画像保存ができない時の解決方法

はじめに

某スクールの学習過程ポートフォリオ作成の際に、Gem 'summernote'を用いて
リッチテキストエディタを実装しました。

開発環境上では画像を含めたテキストの投稿が可能でしたが、
デプロイ後の本番環境にて画像を投稿しようとすると下記エラーが発生し、投稿保存がされませんでした。

(0.5ms)  ROLLBACK
Completed 500 Internal Server Error in 46ms (ActiveRecord: 12.9ms)
ActiveRecord::ValueTooLong (Mysql2::Error: Data too long for column 'article_content' at row 1: 
INSERT INTO `articles` (`admin_id`, `article_title`, `article_content`, `article_image_id`, `created_at`, `updated_at`) VALUES (1, '観葉植物の置き場所はどこがいいか', '<p><img src=\"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QB+RXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAABJADAAIAAAAUAAAAUJKGAAcAAAASAAAAZKACAAQAAAABAAA...(以下長すぎるので省略します)

解決方法

【前提】
・テーブル名はArticleとしてます。(Article=記事の意)。この部分は任意の名前にしてください。

①エラー文の解釈

まず、ターミナルに表示されていたActiveRecord::ValueTooLong (Mysql2::Error: Data too long for column...)このエラー文が解決への糸口になります。

簡潔にいうと、「データが長すぎ」と言われています。
投稿文を保存するarticle_contentのデータ型をtextにしていましたが、これでもまだ足りないと言われているわけです。
代表的なデータ型として短文(1〜255文字)はstring型、長文()はtext型を使うという程度の知識でした。

②変更すべき点

上記内容で、「データが長すぎて保存できない」という問題点がわかりました。
そうしたら収まるように大容量用のデータ型に変更してあげればいいだけです!
下記記述が修正を加えたマイグレーションファイルになります。

(date)_change_column_to_article.rb
class ChangeColumnToArticle < ActiveRecord::Migration[5.2]
  def up
    change_column :articles, :article_content, :text, null: false, limit: 4294967295
  end

  def down
    change_column :articles, :article_content, :text, null: false
  end
end

※以下、修正内容についての詳細です。

デプロイの際にMySQL
MySQLにあるデータ型は以下の通りです。

データ型 解説
CHAR 255Bまでの固定長文字列
VARCHAR 64KBまでの可変長文字列
TINYTE 255Bまでの可変長文字列
TEXT 64KBまでの可変長文字列
MEDIUMTEXT 1.6MBまでの可変長文字列
LONGTEX 4.3GBまでの可変長文字列

この中のLONGTEXTを使用する事にしました。(最大にしておけば足りなくなることはまずないだろうという考え)
ただし前述した通り、Railsの学習をした際にstringとtextくらいしか学習した記憶がなかったため設定方法がわかりませんでした。

調べた結果、結構簡単でリミットをつけるだけでした。
まずカラムに変更を加えるため、以下のようにします。

ターミナル
$ rails g migration ChangeColumnToArticle

すると、以下の内容でマイグレーションファイルが作成されます。

日付_change_column_to_Article.rb
class ChangeColumnToArticle < ActiveRecord::Migration[5.2]
  def change
  end

そして、変更前の記載と変更後の記載を加えます。
ここの記述は冒頭に記載したものと同じになります。

日付_change_column_to_article.rb
class ChangeColumnToArticle < ActiveRecord::Migration[5.2]
※変更を加えた記述
 def up
    change_column :articles, :article_content, :text, null: false, limit: 4294967295
  end

※変更前の記述
  def down
    change_column :articles, :article_content, :text, null: false
  end
end

リミットを書き加えることで、LONGTEXT型にします。
なお、4294967295と言う数字は4294967295バイト(4.3GB)でLONGTEXT型の上限です。
limitの範囲を16777216 ~ 4294967285にするとLONGTEXT型になるそうです。

ターミナル
$ rails db:migrate

変更を反映させて終了です。

そもそも、なぜ開発環境では使えて、本番環境でエラーが出たのか

本番環境ではMySQLを使用していて、MySQLのtext型には最大長が設定されており、半角で65,535文字を超える文字列は扱えません。単純なことでこれが開発環境と本番環境での違いによるエラーの発生の理由でした。(現在の知識・語彙力ではこれが限界です。いずれもっと詳しく解説を加えられたらと思います!)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む