- 投稿日:2020-08-12T21:19:17+09:00
【MySQL】テーブルに主キーを作り忘れた時の対処法
テーブルに主キーを登録し忘れた!とか
中間テーブルを主キーなしで作ってしまって後から必要になった!という時にたとえば
users
という名前のテーブルにid
という主キーになるカラムを追加したかったら> ALTER TABLE users ADD id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;こんな感じ
余談:こんなことをするハメになった経緯
開発環境で中間テーブルを主キーなしで作ってテスト
うん,問題なく動作するよし,Percona XtraDB Clusterで複数台構成になってる本番環境にデプロイ!
すると...MYSQL ERROR, error: Percona-XtraDB-Cluster prohibits use of DML command on a table ([db_name].[table_name]) without an explicit primary key with pxc_strict_mode = ENFORCING or MASTER ...
と怒られた
どうやらペルコナは主キーが無いテーブルはお嫌いらしいです...修正している内にどんどんハマって行って結局2時間くらい彷徨った挙句たどり着いた結論が上のSQL文
超単純だった...
上のSQL文を実行するマイグレーションを追加してなんとか乗り切れましたこの記事誰に需要があるんだろうと思いながらもこの経験を心に刻むためにアウトプット
twitterフォローしてもらえると泣いて喜びます
- 投稿日:2020-08-12T19:28:28+09:00
【Node.js】Expoプッシュ通知を一斉送信するWebAPI|配列を任意の数に分割をする
はじめに
現在Expo ReactNativeを使ってネイティブアプリ開発をしています。
Expoを使ってプッシュ通知を送るためにプッシュ通知のTokenを1つ、1つPOSTリクエストを飛ばしてもいいのですが、Expoの仕様では最大100個のTokenをまとめてPOSTできる。そこでN個ずつに配列を分割して二次元配列にして処理する方法を紹介します。例
以下のような長さ75の配列があるとする、それを10分割して余った分は10個未満になっても分割をする。
今回は長さ75の配列を10個づつ分割して二次元配列にする。処理前
処理後
コード
const main = () =>{ //TOKENにみたて複数の数字を配列にセット let arr = [] for (let i = 0; i < 75; i++) { arr.push(i) } console.log(arr) let result_arr = [] //分割数 const division_count = 10 //配列の数を分割数で割った値を切り上げた値 const add_arr_count = Math.ceil(arr.length / division_count) //add_arr_countの分だけ空配列を追加する for (let i = 0; i < add_arr_count; i++) { result_arr.push([]) } //いい感じに分割して配列にいれる arr.forEach((item,index)=>{ result_arr[Math.floor(index/division_count)].push(item) }) console.log(result_arr) } (async () => { main() })()Expoを使って実際に通知を送る
私の環境ではNode.jsを使ってWebAPIを作り、まとめて送信できるようにしています。
また、Token一覧を管理しているのはMySQLを使っています。Request bodyに
プッシュ通知のタイトルを設定するpush_title
とプッシュ通知の本文部分にあたるpush_body
載せてください※本物のコードは外部から実行できないようにセキュリティ対策をしています
コード
const express = require('express') // expressモジュールを読み込む const cors = require('cors') //クロスドメインでアクセスを許可する系のやつ const bodyParser = require('body-parser') //いい感じにGET POSTを解釈するやつ const util = require('util') // SQL Async/Await const axios = require('axios')//npm install axios const mysql = require('mysql') const multer = require('multer') // multerモジュールを読み込む これがないとBODYの中身をうまく読み取らない //↑ 各種、「npm install」してください //↑ 各種、「npm install」してください //↑ 各種、「npm install」してください // 例1 npm i express // 例2 npm i cors const app = express() // expressアプリを生成する app.use(bodyParser()) app.use(express.static('web')) // webフォルダの中身を公開する app.use(cors())//CROS許可 app.use(multer().none()) // multerでブラウザから送信されたデータを解釈する //サーバの受付ポート番号、SQL接続情報、設定ファイル読み込み const config = require('./server_config.json') // config.server.portのポートでサーバを立てる app.listen(config.server.port, () => console.log('Listening on port ' + config.server.port)) //MySQL接続情報Async/Await★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ const pool_config = { host: config.sql.host, user: config.sql.user, password: config.sql.password, port: config.sql.port, database: config.sql.database, timezone: config.sql.timezone //timezoneの指定省略の場合はシステムローカルになる } //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //汎用的にMySQLを発行する const runQuery = async (sql, data) => { console.log('runQuery...') console.log('sql: ' + sql) console.log('data: ' + data) const pool = mysql.createPool(pool_config) pool.query = util.promisify(pool.query)//これないと動かない const run_sql = mysql.format(sql, data) console.log('発行されたquery:\n' + run_sql + '\n') const result = await pool.query(run_sql) // console.log(JSON.stringify(result)) pool.end() // mysqlのコネクションのプロセスを終了させる。 return result } const uuid = require('node-uuid') app.post('/api/v1/expoPushNotice', (req, res, next) => { (async () => { console.log('/api/v1/expoPushNotice...') //私の環境ではMySQLでpush_tokenというTableを作ってそこでTokenを保存しています let push_token_list = await runQuery( 'select `push_token` from `push_token`', [] ) //通知を送るtoken let to_tokens = [] //分割数 const division_count = 100 //配列の追加数 切り上げた値の数だけ配列を追加 const add_arr_count = Math.ceil(push_token_list.length / division_count) console.log('add_arr_countの文だけから配列を追加する') //add_arr_countの文だけから配列を追加する for (let i = 0; i < add_arr_count; i++) { to_tokens.push([]) } push_token_list.forEach((item, index) => { to_tokens[Math.floor(index/division_count)].push(item.push_token) }) console.log('to_tokens: ') console.log(to_tokens) //APIコール console.log('pushSend...') const req_url = 'https://exp.host/--/api/v2/push/send' const headers = { headers: { Accept: 'application/json', 'Accept-encoding': 'gzip, deflate', 'Content-Type': 'application/json', }, } //分割した分で別々にPOSTリクエストを飛ばす for (let i = 0; i < to_tokens.length; i++) { //bodyに好きなデータを載せると、アプリ側でいろいろできます。 const result = await axios.post( req_url, { 'to': to_tokens[i], 'sound': 'default', 'title': req.body.push_title, 'body': req.body.push_body, 'data': { }, }, headers ) console.log('result: ') console.log(result) } res.json({ status: 200, // message: 'リクエストは正常に受信されました', }) })(res, next).catch((e) => { console.log('サーバエラー : ' + e) console.log('res : ' + res) console.log('e : ' + e) res.json({ status: 500, message: 'サーバエラー\n' + next, }) }) })Tokenを保存しているDB情報
CREATE TABLE `push_token` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `push_token` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `push_token` (`push_token`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;サーバの設定ファイルを記述しているJSONファイル
{ "sql": { "host": "localhost", "user": "hoge", "password": "hoge", "port": 8889, "database": "fuga", "timezone": "jst" }, "server":{ "port": 3003 } }
- 投稿日:2020-08-12T15:09:35+09:00
laravel SQLSTATE[HY000] [2002] Connection refused
SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.tables where table_schema = laravel and table_name = migrations and table_type = 'BASE TABLE')エラー対処
メモ
.envの修正もしたのに解決しなかった場合、下記コマンド実行したら解消しました。
php artisan key:generate php artisan cache:clear php artisan route:clear php artisan config:clear php artisan view:clear