ndjson は複数の JSON データが改行区切りで集まった文字列情報です。例えば、次です。
{"datetime":"2021-10-06T11:04:19.461065+09:00","message":"課金処理","level_name":"INFO"} {"datetime":"2021-10-06T11:04:19.467941+09:00","message":"file_get_contents(): Read of 8192 bytes failed with errno=21 Is a directory...","level_name":"ERROR"}
ndjson
例にあるようにログを構造的に記録していく時に便利です。もし普通の JSON 形式ですとログファイル全体を読み直すか、ファイルの末尾を毎回 JSON として成立する様に書き込まなければなくなり、不穏な挙動を示します(一貫性等考えなくていい単純な行追記の方が楽という懐事情も)。
毎回毎回 jq を使ってコマンドラインでログの内容を確認するのも手ですが、ブラウザ上から簡易に確認したい時もあります。そういった時は次の様なコードが役に立ちます。
stedolan/jq: Command-line JSON processor
1 2 3 | < label for = "" >プロパティ< input type = "text" id = "key" ></ label > < label for = "" >フィルタ< input type = "text" id = "query" ></ label > < pre id = "display" ></ pre > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | /** axios や埋め込みなどでどこからか取得した ndJSON 形式のデータ */ const ndJsonContent = `{ "datetime" : "2021-10-06T11:04:19.461065+09:00" , "message" : "課金処理" , "level_name" : "INFO" } { "datetime" : "2021-10-06T11:04:19.467941+09:00" , "message" : "file_get_contents(): Read of 8192 bytes failed with errno=21 Is a directory..." , "level_name" : "ERROR" }` .split( "\n" ) // 行単位で分割 .filter(l=>l) // 空行を除去 .map(line => JSON.parse(line)); // 各行を JSON として解釈 /** 結果を表示する要素 */ const dEl = document.getElementById( 'display' ); /** filterを欠けるプロパティを value に持つ input 要素 */ const kEl = document.getElementById( 'key' ); /** filterに使う文字列を value に持つ input 要素 */ const qEl = document.getElementById( 'query' ); // 初期化 dEl.innerText = JSON.stringify(ndJsonContent, null , 2); /** kEl, qEl の value を見て、表示を適切に変更する関数 */ const updater = () => { dEl.innerText = JSON.stringify( // ndJSON のうち、kEl で指定されたプロパティを qEl で絞り込む // ここでは単に一列目のプロパティアクセスですが、dot-prop 等を使って1文字列でネストさせることもできます // filter のみを使っていますが、同様に任意のプロパティと任意の値と配列メソッド(map等)を組み合わせるとより多様なことができます。 ndJsonContent.filter(item=>item[kEl.value].includes(qEl.value)), null , 2 ); } // ↑の表示更新関数を Event として登録 qEl.addEventListener( 'input' ,updater) kEl.addEventListener( 'input' ,updater) |
実際に動かしたデモが次です
こんな感じにすると次の様に jq 的なクエリが作れます。例は単に一つの filter ですが、map を使う、範囲指定をする、クエリ数や種類を可変にするなど色々拡張できます。