20200812のMySQLに関する記事は3件です。

【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フォローしてもらえると泣いて喜びます

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

【Node.js】Expoプッシュ通知を一斉送信するWebAPI|配列を任意の数に分割をする

はじめに

現在Expo ReactNativeを使ってネイティブアプリ開発をしています。
Expoを使ってプッシュ通知を送るためにプッシュ通知のTokenを1つ、1つPOSTリクエストを飛ばしてもいいのですが、Expoの仕様では最大100個のTokenをまとめてPOSTできる。そこでN個ずつに配列を分割して二次元配列にして処理する方法を紹介します。

以下のような長さ75の配列があるとする、それを10分割して余った分は10個未満になっても分割をする。
今回は長さ75の配列を10個づつ分割して二次元配列にする。

処理前

スクリーンショット 2020-08-12 午後6.59.47.png

処理後

スクリーンショット 2020-08-12 午後7.02.02.png

コード

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
  }
}

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

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 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む