Edited at

JavascriptでJSON


はじめに

 JavascriptでJSONを扱う機会が多いのでまとめてみます。mapとかreduceとかそろそろ使いこなせるようになりたいです。


前提

 扱うJSONは下のような感じにしました。気分です。最近iPod卒業して以下の3つを品定め中だからです。ランキングは一部抜粋、今Apple Musicに傾きつつあるので、他のやつのランキングはスキップで。まあだいたい同じですし。


var sample = {
Music_Services:[
{
Service: "Apple Music",
Company: "Apple",
Top_Song_Ranking:{
observation_date: "2019-02-09",
ranking:[
{
artist: "あいみょん",
song: "マリーゴールド",
rank: 1
},
{
artist: "ONE OK ROCK",
song: "Stand Out Fit In",
rank: 2
},
{
artist: "あいみょん",
song: "今夜このまま",
rank: 3
},
{
artist: "エド・シーラン",
song: "Shape of You",
rank: 7
},
{
artist: "あいみょん",
song: "愛を伝えたいだとか",
rank: 9
}
]
}
},
{
Service: "Google Play Music",
Company: "Google",
Top_Song_Ranking: null
},
{
Service: "Spotify",
Company: "Spotify AB",
Top_Song_Ranking: null
}
]
}

* データ構造は適当に作ったものでApple MusicのAPI定義とかに合わせたりしてません。


参照


レコード参照

「音楽サービスのどんなデータ入ってるのかザーッと見たい」

sample["Music_Services"].forEach((item) => {

console.log(item)
})

{ Service: 'Apple Music',

Company: 'Apple',
Top_Song_Ranking:
{ observation_date: '2019-02-09',
ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }
{ Service: 'Google Play Music',
Company: 'Google',
Top_Song_Ranking: null }
{ Service: 'Spotify',
Company: 'Spotify AB',
Top_Song_Ranking: null }

[Object]の中身表示したかったらconsole.log(JSON.stringify(item)) にすれば見れますね。


プロパティ参照

「一覧だと見づらいからどんな属性があるかだけ見たい」

var firstService = sample["Music_Services"][0]

Object.keys(firstService).forEach((data) => {
console.log(data);
})

Service

Company
Top_Song_Ranking

「もっと深い属性が見たい」

Object.keys(firstService["Top_Song_Ranking"]).forEach((data) => {

console.log(data);
})
console.log("====")

var firstSong = firstService["Top_Song_Ranking"]["ranking"][0]
Object.keys(firstSong).forEach((data) => {
console.log(data);
})

observation_date

ranking
====
artist
song
rank

 基本的に1つ目のレコードだけサンプル的にとってきて中を覗く感じです。レコードによってプロパティに過不足ある場合とかは対象外で。


検索


単一検索

「Apple Musicの情報だけ欲しい」

const AppleMusic = sample["Music_Services"].find((item, index) => {

return (item.Service === "Apple Music")
})
/*こっちでもおなじ
const AppleMusic = sample["Music_Services"].find((item, index) => {
if(item.Service === "Apple Music") return true
})
*/

console.log(AppleMusic)

{ Service: 'Apple Music',

Company: 'Apple',
Top_Song_Ranking:
{ observation_date: '2019-02-09',
ranking: [ [Object], [Object], [Object], [Object], [Object] ] } }

ここからはApple Musicしか眼中に入れません。

なので、変数 "AppleMusic"を使いまわします。


複数検索

「あいみょんの曲ってどんぐらいランキング入ってるんだろ」

const Aimyon_Songs = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {

return (item.artist === "あいみょん")
})

console.log(Aimyon_Songs)

[ { artist: 'あいみょん', song: 'マリーゴールド', rank: 1 },

{ artist: 'あいみょん', song: '今夜このまま', rank: 3 },
{ artist: 'あいみょん', song: '愛を伝えたいだとか', rank: 9 } ]

*本当は他にももっと入ってますよ

「英語タイトルの曲どんくらいランキング入ってるんだろ」

const English_Titles = AppleMusic["Top_Song_Ranking"]["ranking"].filter((item, index) => {

return (item.song.match(/[a-zA-Z]/))
})

console.log(English_Titles)

[ { artist: 'ONE OK ROCK', song: 'Stand Out Fit In', rank: 2 },

{ artist: 'エド・シーラン', song: 'Shape of You', rank: 7 } ]

*おまけ

filterは複数検索の時ですね。findも兼ねますが、なんとなく使い分けたいなと。


制限

「曲名だけ一覧でバーっと見たい」

const song_names = AppleMusic["Top_Song_Ranking"]["ranking"].map(x => x["song"])

console.log(song_names)

[ 'マリーゴールド',

'Stand Out Fit In',
'今夜このまま',
'Shape of You',
'愛を伝えたいだとか' ]

 mapって主にこういうときに使うイメージですね。他にもあるかな。


集約

「結局ランキングにどういうアーティストが何曲ずつくらい入ってるんだろ」

const summary = AppleMusic["Top_Song_Ranking"]["ranking"].reduce((accum, current)=> {

//同じアーティスト名がaccumの中にあるか検索
const element = accum.find((item) => {return item.artist === current.artist});
//あったらカウントだけする
if(element){ element.count ++}
//なかったらaccumに追加してあげる
else{
accum.push({
artist: current.artist,
count: 1
});
}
return accum
}, []);

console.log(summary)

[ { artist: 'あいみょん', count: 3 },

{ artist: 'ONE OK ROCK', count: 1 },
{ artist: 'エド・シーラン', count: 1 } ]

 reduceは集約するときに使う感じですね。forEachで足していくほうがわかりやすいんですけどreduceが使えたらかっこいいなと。まだまだ慣れません。


おわりに

 reduceはやはり小難しい。あいみょんすごい。もう少し追記していきたいと思っているところです。