Python Boto3를 이용한 Spotify 음악데이터 DynamoDB 저장&활용

2020-06-07

.

Data_Engineering_TIL(20200607)

[참고사항]

  • ‘Spotify API 음악데이터 저장을 위한 python 기본활용’를 이어서 참고할 것

  • URL : https://minman2115.github.io/DE_TIL91/

[학습내용]

  • 먼저 shell에서 aws configure로 IAM credential을 등록해준다.

  • 등록한 아이디에 해당하는 계정 콘솔로가서 DynamoDB를 아래 그림과 같이 생성해준다.

테이블 이름 : pms-dynamodb-test, 파티션 키 : artist_id (문자열), 정렬 키 : id (문자열), 총 읽기/쓰기 용량 : 5, 읽기/쓰기모드 : provisioned, 암호화 옵션 : 기본값

makedynamo

** 참고사항

index를 만들어서(create index) 같은 테이블에서도 여러개의 파티션 키를 지정해서 쓸 수 있다.

아래그림과 같은 방식으로 만들어주면 되는데 이번 실습에서는 만들지 않고 진행한다.

makeindex

  • 그러면 아래와 같이 코딩해서 실행해본다.

하나의 아티스트에 대해서 track을 id값으로 나누어서 데이터를 저장하는 것이고, put item이라는 것을 이용해서 single 단위로 데이터를 넣는 것이다.

import sys
import os
import boto3
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "pms-rdstest-rds.xxxxxxxxxxxxxxxx.ap-northeast-2.rds.amazonaws.com"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"


def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    try:
        conn = pymysql.connect(host, user=username, passwd=password, db=database, port=port, use_unicode=True, charset='utf8')
        cursor = conn.cursor()
    except:
        logging.error("could not connect to rds")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    table = dynamodb.Table('pms-dynamodb-test')

    cursor.execute('SELECT id FROM pmstest.artists limit 1')
    ## 아티스트 1명에 대해서만 시범적으로 돌려보자

    for (artist_id, ) in cursor.fetchall():
        URL = "https://api.spotify.com/v1/artists/{}/top-tracks".format(artist_id)
        params = {'country': 'US'}

        r = requests.get(URL, params=params, headers=headers)
        raw = json.loads(r.text)

        print(raw)

        for track in raw['tracks']:
            data = {'artist_id': artist_id}
            data.update(track)
            table.put_item(Item=data)

    return None

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

실행 후 아래 그림과 같이 다이나모 디비에 10개의 데이터가 들어온 것을 확인할 수 있다.

image

image

다이나모 디비 테이블에 country 인덱스도 추가해서 돌리고 싶을때는 아래와 같이 코딩해서 실행하면 된다.

import sys
import os
import boto3
import requests
import base64
import json
import logging
import pymysql
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

host = "pms-rdstest-rds.xxxxxxxxxxxxxxxx.ap-northeast-2.rds.amazonaws.com"
port = 3306
username = "admin"
database = "pmstest"
password = "xxxxxxxxxxxxxxxxxxxxxxxxx"

client_id = "xxxxxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"


def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    try:
        conn = pymysql.connect(host, user=username, passwd=password, db=database, port=port, use_unicode=True, charset='utf8')
        cursor = conn.cursor()
    except:
        logging.error("could not connect to rds")
        sys.exit(1)

    headers = get_headers(client_id, client_secret)

    table = dynamodb.Table('pms-dynamodb-test')

    cursor.execute('SELECT id FROM pmstest.artists')

    countries = ['US', 'CA']
    for country in countries:
        for (artist_id, ) in cursor.fetchall():
            URL = "https://api.spotify.com/v1/artists/{}/top-tracks".format(artist_id)
            params = {'country': 'US'}

            r = requests.get(URL, params=params, headers=headers)
            raw = json.loads(r.text)

            for track in raw['tracks']:
                data = {'artist_id': artist_id, 'country': country}
                data.update(track)
                table.put_item(Item=data)
    
    return None

def get_headers(client_id, client_secret):
    endpoint = "https://accounts.spotify.com/api/token"
    encoded = base64.b64encode("{}:{}".format(client_id, client_secret).encode('utf-8')).decode('ascii')
    headers = {"Authorization": "Basic {}".format(encoded)}
    payload = {"grant_type": "client_credentials"}
    r = requests.post(endpoint, data=payload, headers=headers)
    access_token = json.loads(r.text)['access_token']
    headers = {"Authorization": "Bearer {}".format(access_token)}
    return headers

if __name__=='__main__':
    main()

그러면 저장한 데이터를 아래와 같이 코드를 작성하여 특정 아이템을 get해보자.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.get_item(Key={'artist_id':'4H2b90USTVSstPktwUsDZE'})

    print(response)

    return None

if __name__=='__main__':
    main()
코드를 실행하면 아래와 같이 애러 메세지가  것이다.

Traceback (most recent call last):
  File "dynamodb_12.8.py", line 23, in <module>
    main()
  File "dynamodb_12.8.py", line 16, in main
    response = table.get_item(Key={'artist_id':'4H2b90USTVSstPktwUsDZE'})
  File "C:\ProgramData\Anaconda3\lib\site-packages\boto3\resources\factory.py", line 520, in do_action
    response = action(self, *args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\boto3\resources\action.py", line 83, in __call__
    response = getattr(parent.meta.client, operation_name)(**params)
  File "C:\ProgramData\Anaconda3\lib\site-packages\botocore\client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\botocore\client.py", line 661, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the GetItem operation: The provided key element does not match the schema

다이나모 디비에서 키값을 artist_id로 해놓은 것도 있지만 id도 있었다. 따라서 get item을 하려면 아래 코드와 같이 id까지 전부 있어야지만 애러 없이 잘 가져올 수 있다.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.get_item(Key={'artist_id':'4H2b90USTVSstPktwUsDZE','id':'0S84tthIVDN3rEVOejJVsM'})

    print(response)

    return None

if __name__=='__main__':
    main()

실행결과는 아래와 같다.

{'Item': {'is_playable': True, 'duration_ms': Decimal('289680'), 'external_ids': {'isrc': 'USWB19700654'}, 'uri': 'spotify:track:0S84tthIVDN3rEVOejJVsM', 'name': 'In All My Wildest Dreams', 'album': {'total_tracks': Decimal('15'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273cf2c98d323ca13efb591780f', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02cf2c98d323ca13efb591780f', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851cf2c98d323ca13efb591780f', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1997-07-25', 'name': 'Sample This', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/0sQhUzdfLrBtQ8v2Hsl6Pp', 'id': '0sQhUzdfLrBtQ8v2Hsl6Pp', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'uri': 'spotify:album:0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'popularity': Decimal('38'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0S84tthIVDN3rEVOejJVsM', 'track_number': Decimal('7'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0S84tthIVDN3rEVOejJVsM'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2d4692c1ca3c983fd59c5c8ac81f4278d2d6bda9?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0S84tthIVDN3rEVOejJVsM', 'explicit': False, 'type': 'track'}, 'ResponseMetadata': {'RequestId': 'SJHE8GK8N3OOM586BPSIFLLU1NVV4KQNSO5AEMVJF66Q9ASUAAJG', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': 'SJHE8GK8N3OOM586BPSIFLLU1NVV4KQNSO5AEMVJF66Q9ASUAAJG', 'x-amz-crc32': '3653699256', 'content-type': 'application/x-amz-json-1.0', 'content-length': '2238', 'date': 'Sun, 07 Jun 2020 13:43:06 GMT'}, 'RetryAttempts': 0}}

그러나 현실적으로 쓰일때는 artist_id나 id 값을 전부 알아서 하드코딩하는 일은 거의 없을 것이다.

현실적으로는 artist_id나 id 둘중하나만 알아서 필터링해서 가져오는 경우가 많을 것이다.

다이나모 디비의 boto3에서는 query와 scan이라는 것을 지원하는데 이걸 활용하면 된다.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.query(KeyConditionExpression=Key('artist_id').eq('4H2b90USTVSstPktwUsDZE'))
    # artist_id가 4H2b90USTVSstPktwUsDZE인것(eq=equal)을 쿼리

    print(response)

    return None

if __name__=='__main__':
    main()

실행결과는 아래와 같다.

해당 artist_id에 대한 아이템을 가져오게 된다.

{'Items': [{'is_playable': True, 'duration_ms': Decimal('289680'), 'external_ids': {'isrc': 'USWB19700654'}, 'uri': 'spotify:track:0S84tthIVDN3rEVOejJVsM', 'name': 'In All My Wildest Dreams', 'album': {'total_tracks': Decimal('15'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273cf2c98d323ca13efb591780f', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02cf2c98d323ca13efb591780f', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851cf2c98d323ca13efb591780f', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1997-07-25', 'name': 'Sample This', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/0sQhUzdfLrBtQ8v2Hsl6Pp', 'id': '0sQhUzdfLrBtQ8v2Hsl6Pp', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'uri': 'spotify:album:0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'popularity': Decimal('38'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0S84tthIVDN3rEVOejJVsM', 'track_number': Decimal('7'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0S84tthIVDN3rEVOejJVsM'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2d4692c1ca3c983fd59c5c8ac81f4278d2d6bda9?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0S84tthIVDN3rEVOejJVsM', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('233920'), 'external_ids': {'isrc': 'USPRA0600008'}, 'uri': 'spotify:track:0WU4L5lelOjccOeydME65Z', 'name': "Everybody's Talking", 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('48'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0WU4L5lelOjccOeydME65Z', 'track_number': Decimal('8'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0WU4L5lelOjccOeydME65Z'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/3bdbcd65ca07b1f9c93b8a1b7bf0ee3c74026c7b?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0WU4L5lelOjccOeydME65Z', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('307333'), 'external_ids': {'isrc': 'USPRA0600004'}, 'uri': 'spotify:track:0g7z3mwBdTn60MIL30TxhZ', 'name': 'Rio De Janeiro Blue', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('49'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0g7z3mwBdTn60MIL30TxhZ', 'track_number': Decimal('4'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0g7z3mwBdTn60MIL30TxhZ'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2db4951d4ea0d7e870e7001514b9436ddb35d06e?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0g7z3mwBdTn60MIL30TxhZ', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('297813'), 'external_ids': {'isrc': 'USPRA0600006'}, 'uri': 'spotify:track:1S0Gx1R13Somg6WKobPcMc', 'name': 'See Line Woman', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('38'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/1S0Gx1R13Somg6WKobPcMc', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/1S0Gx1R13Somg6WKobPcMc'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/222a0aeb60863fea7c108492b9ad4c8743db82a3?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '1S0Gx1R13Somg6WKobPcMc', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('291266'), 'external_ids': {'isrc': 'USWB18900034'}, 'uri': 'spotify:track:2MX5LrnzqPKdiyxwFez2Ma', 'name': 'U Turn', 'album': {'total_tracks': Decimal('10'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273b693653b1ee0b7108208a568', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02b693653b1ee0b7108208a568', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851b693653b1ee0b7108208a568', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1989-03-10', 'name': 'Spellbound', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/7q0WkXf88v6eTtgqrckZHH', 'id': '7q0WkXf88v6eTtgqrckZHH', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/7q0WkXf88v6eTtgqrckZHH'}, 'uri': 'spotify:album:7q0WkXf88v6eTtgqrckZHH'}, 'popularity': Decimal('40'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/2MX5LrnzqPKdiyxwFez2Ma', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/2MX5LrnzqPKdiyxwFez2Ma'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2b2d2357515b9165743500252b3aecd17fcc3b7b?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '2MX5LrnzqPKdiyxwFez2Ma', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('343480'), 'external_ids': {'isrc': 'USPRA9900006'}, 'uri': 'spotify:track:3CObSbajZV0iSviNXZFhfk', 'name': 'When Your Life Was Low', 'album': {'total_tracks': Decimal('11'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b2731f0ff9a82f509cfc550d15dc', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e021f0ff9a82f509cfc550d15dc', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d000048511f0ff9a82f509cfc550d15dc', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'release_date': '1999', 'name': 'The Song Lives On', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/1hRQZQa8ryz2oOunpCMf0Y', 'id': '1hRQZQa8ryz2oOunpCMf0Y', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1hRQZQa8ryz2oOunpCMf0Y'}, 'uri': 'spotify:album:1hRQZQa8ryz2oOunpCMf0Y'}, 'popularity': Decimal('36'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/3CObSbajZV0iSviNXZFhfk', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/3CObSbajZV0iSviNXZFhfk'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/8ff39f5cfc1e03907061eac8057668b6a58b31a8?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '3CObSbajZV0iSviNXZFhfk', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('253746'), 'external_ids': {'isrc': 'USPRA0600009'}, 'uri': 'spotify:track:50vVWF1lAFb1A4ZnIQWsr1', 'name': 'When I Need You', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('41'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/50vVWF1lAFb1A4ZnIQWsr1', 'track_number': Decimal('9'), 'external_urls': {'spotify': 'https://open.spotify.com/track/50vVWF1lAFb1A4ZnIQWsr1'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/beb8a06964dbc83fc017382775029b32c445648d?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '50vVWF1lAFb1A4ZnIQWsr1', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('240666'), 'external_ids': {'isrc': 'DEA890500467'}, 'uri': 'spotify:track:5G4mD6dNtV9V30npBbAj0i', 'name': 'One Day I Fly Away', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273a0a3e94b1ee94e8a284f84db', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02a0a3e94b1ee94e8a284f84db', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851a0a3e94b1ee94e8a284f84db', 'height': Decimal('64')}], 'artists': [{'name': 'Nils Landgren', 'href': 'https://api.spotify.com/v1/artists/6B3ZWSop1mrJd71rwFozVP', 'id': '6B3ZWSop1mrJd71rwFozVP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/6B3ZWSop1mrJd71rwFozVP'}, 'uri': 'spotify:artist:6B3ZWSop1mrJd71rwFozVP'}, {'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '2005-10-28', 'name': 'Creole Love Call', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/1aV2jCH2ntuiZTpcrPcQvn', 'id': '1aV2jCH2ntuiZTpcrPcQvn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1aV2jCH2ntuiZTpcrPcQvn'}, 'uri': 'spotify:album:1aV2jCH2ntuiZTpcrPcQvn'}, 'popularity': Decimal('44'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Nils Landgren', 'href': 'https://api.spotify.com/v1/artists/6B3ZWSop1mrJd71rwFozVP', 'id': '6B3ZWSop1mrJd71rwFozVP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/6B3ZWSop1mrJd71rwFozVP'}, 'uri': 'spotify:artist:6B3ZWSop1mrJd71rwFozVP'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/5G4mD6dNtV9V30npBbAj0i', 'track_number': Decimal('7'), 'external_urls': {'spotify': 'https://open.spotify.com/track/5G4mD6dNtV9V30npBbAj0i'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/870bf61e6d74ac3c11557bc4cb90a0e38f575669?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '5G4mD6dNtV9V30npBbAj0i', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('349053'), 'external_ids': {'isrc': 'USPRA9900005'}, 'uri': 'spotify:track:5jdyZZl1zFVdzFvN2cWHWE', 'name': 'Street Life', 'album': {'total_tracks': Decimal('11'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b2731f0ff9a82f509cfc550d15dc', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e021f0ff9a82f509cfc550d15dc', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d000048511f0ff9a82f509cfc550d15dc', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'release_date': '1999', 'name': 'The Song Lives On', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/1hRQZQa8ryz2oOunpCMf0Y', 'id': '1hRQZQa8ryz2oOunpCMf0Y', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1hRQZQa8ryz2oOunpCMf0Y'}, 'uri': 'spotify:album:1hRQZQa8ryz2oOunpCMf0Y'}, 'popularity': Decimal('34'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/5jdyZZl1zFVdzFvN2cWHWE', 'track_number': Decimal('5'), 'external_urls': {'spotify': 'https://open.spotify.com/track/5jdyZZl1zFVdzFvN2cWHWE'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/d1f1745e941edf1554b8d5e6e3a2362384feeb37?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '5jdyZZl1zFVdzFvN2cWHWE', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('308640'), 'external_ids': {'isrc': 'USWB10000263'}, 'uri': 'spotify:track:6rtGTWFi7HGoK9nCU7gsVA', 'name': 'Leading Me Back to You', 'album': {'total_tracks': Decimal('10'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273b693653b1ee0b7108208a568', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02b693653b1ee0b7108208a568', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851b693653b1ee0b7108208a568', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1989-03-10', 'name': 'Spellbound', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/7q0WkXf88v6eTtgqrckZHH', 'id': '7q0WkXf88v6eTtgqrckZHH', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/7q0WkXf88v6eTtgqrckZHH'}, 'uri': 'spotify:album:7q0WkXf88v6eTtgqrckZHH'}, 'popularity': Decimal('44'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Michael Franks', 'href': 'https://api.spotify.com/v1/artists/0AVE7rDx4X9w0pW1XlN1om', 'id': '0AVE7rDx4X9w0pW1XlN1om', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0AVE7rDx4X9w0pW1XlN1om'}, 'uri': 'spotify:artist:0AVE7rDx4X9w0pW1XlN1om'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/6rtGTWFi7HGoK9nCU7gsVA', 'track_number': Decimal('5'), 'external_urls': {'spotify': 'https://open.spotify.com/track/6rtGTWFi7HGoK9nCU7gsVA'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/b7934da9819d134159f3ee9e887e48231c958518?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '6rtGTWFi7HGoK9nCU7gsVA', 'explicit': False, 'type': 'track'}], 'Count': 10, 'ScannedCount': 10, 'ResponseMetadata': {'RequestId': '7H6M7F5KLI7CU874978HCHV70NVV4KQNSO5AEMVJF66Q9ASUAAJG', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '7H6M7F5KLI7CU874978HCHV70NVV4KQNSO5AEMVJF66Q9ASUAAJG', 'x-amz-crc32': '1967264896', 'content-type': 'application/x-amz-json-1.0', 'content-length': '27027', 'date': 'Sun, 07 Jun 2020 13:52:02 GMT'}, 'RetryAttempts': 0}}

또는 그중에서 Items만 가져올 수도 있다.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.query(KeyConditionExpression=Key('artist_id').eq('4H2b90USTVSstPktwUsDZE'))
    # artist_id가 4H2b90USTVSstPktwUsDZE인것(eq=equal)을 쿼리

    print(response['Items'])
    print(len(response['Items']))

    return None

if __name__=='__main__':
    main()

실행결과는 아래와 같다.

[{'is_playable': True, 'duration_ms': Decimal('289680'), 'external_ids': {'isrc': 'USWB19700654'}, 'uri': 'spotify:track:0S84tthIVDN3rEVOejJVsM', 'name': 'In All My Wildest Dreams', 'album': {'total_tracks': Decimal('15'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273cf2c98d323ca13efb591780f', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02cf2c98d323ca13efb591780f', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851cf2c98d323ca13efb591780f', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1997-07-25', 'name': 'Sample This', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/0sQhUzdfLrBtQ8v2Hsl6Pp', 'id': '0sQhUzdfLrBtQ8v2Hsl6Pp', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'uri': 'spotify:album:0sQhUzdfLrBtQ8v2Hsl6Pp'}, 'popularity': Decimal('38'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0S84tthIVDN3rEVOejJVsM', 'track_number': Decimal('7'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0S84tthIVDN3rEVOejJVsM'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2d4692c1ca3c983fd59c5c8ac81f4278d2d6bda9?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0S84tthIVDN3rEVOejJVsM', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('233920'), 'external_ids': {'isrc': 'USPRA0600008'}, 'uri': 'spotify:track:0WU4L5lelOjccOeydME65Z', 'name': "Everybody's Talking", 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('48'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0WU4L5lelOjccOeydME65Z', 'track_number': Decimal('8'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0WU4L5lelOjccOeydME65Z'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/3bdbcd65ca07b1f9c93b8a1b7bf0ee3c74026c7b?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0WU4L5lelOjccOeydME65Z', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('307333'), 'external_ids': {'isrc': 'USPRA0600004'}, 'uri': 'spotify:track:0g7z3mwBdTn60MIL30TxhZ', 'name': 'Rio De Janeiro Blue', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('49'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0g7z3mwBdTn60MIL30TxhZ', 'track_number': Decimal('4'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0g7z3mwBdTn60MIL30TxhZ'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2db4951d4ea0d7e870e7001514b9436ddb35d06e?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0g7z3mwBdTn60MIL30TxhZ', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('297813'), 'external_ids': {'isrc': 'USPRA0600006'}, 'uri': 'spotify:track:1S0Gx1R13Somg6WKobPcMc', 'name': 'See Line Woman', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('38'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/1S0Gx1R13Somg6WKobPcMc', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/1S0Gx1R13Somg6WKobPcMc'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/222a0aeb60863fea7c108492b9ad4c8743db82a3?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '1S0Gx1R13Somg6WKobPcMc', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('291266'), 'external_ids': {'isrc': 'USWB18900034'}, 'uri': 'spotify:track:2MX5LrnzqPKdiyxwFez2Ma', 'name': 'U Turn', 'album': {'total_tracks': Decimal('10'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273b693653b1ee0b7108208a568', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02b693653b1ee0b7108208a568', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851b693653b1ee0b7108208a568', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1989-03-10', 'name': 'Spellbound', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/7q0WkXf88v6eTtgqrckZHH', 'id': '7q0WkXf88v6eTtgqrckZHH', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/7q0WkXf88v6eTtgqrckZHH'}, 'uri': 'spotify:album:7q0WkXf88v6eTtgqrckZHH'}, 'popularity': Decimal('40'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/2MX5LrnzqPKdiyxwFez2Ma', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/2MX5LrnzqPKdiyxwFez2Ma'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2b2d2357515b9165743500252b3aecd17fcc3b7b?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '2MX5LrnzqPKdiyxwFez2Ma', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('343480'), 'external_ids': {'isrc': 'USPRA9900006'}, 'uri': 'spotify:track:3CObSbajZV0iSviNXZFhfk', 'name': 'When Your Life Was Low', 'album': {'total_tracks': Decimal('11'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b2731f0ff9a82f509cfc550d15dc', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e021f0ff9a82f509cfc550d15dc', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d000048511f0ff9a82f509cfc550d15dc', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'release_date': '1999', 'name': 'The Song Lives On', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/1hRQZQa8ryz2oOunpCMf0Y', 'id': '1hRQZQa8ryz2oOunpCMf0Y', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1hRQZQa8ryz2oOunpCMf0Y'}, 'uri': 'spotify:album:1hRQZQa8ryz2oOunpCMf0Y'}, 'popularity': Decimal('36'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/3CObSbajZV0iSviNXZFhfk', 'track_number': Decimal('6'), 'external_urls': {'spotify': 'https://open.spotify.com/track/3CObSbajZV0iSviNXZFhfk'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/8ff39f5cfc1e03907061eac8057668b6a58b31a8?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '3CObSbajZV0iSviNXZFhfk', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('253746'), 'external_ids': {'isrc': 'USPRA0600009'}, 'uri': 'spotify:track:50vVWF1lAFb1A4ZnIQWsr1', 'name': 'When I Need You', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('41'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/50vVWF1lAFb1A4ZnIQWsr1', 'track_number': Decimal('9'), 'external_urls': {'spotify': 'https://open.spotify.com/track/50vVWF1lAFb1A4ZnIQWsr1'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/beb8a06964dbc83fc017382775029b32c445648d?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '50vVWF1lAFb1A4ZnIQWsr1', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('240666'), 'external_ids': {'isrc': 'DEA890500467'}, 'uri': 'spotify:track:5G4mD6dNtV9V30npBbAj0i', 'name': 'One Day I Fly Away', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273a0a3e94b1ee94e8a284f84db', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02a0a3e94b1ee94e8a284f84db', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851a0a3e94b1ee94e8a284f84db', 'height': Decimal('64')}], 'artists': [{'name': 'Nils Landgren', 'href': 'https://api.spotify.com/v1/artists/6B3ZWSop1mrJd71rwFozVP', 'id': '6B3ZWSop1mrJd71rwFozVP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/6B3ZWSop1mrJd71rwFozVP'}, 'uri': 'spotify:artist:6B3ZWSop1mrJd71rwFozVP'}, {'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '2005-10-28', 'name': 'Creole Love Call', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/1aV2jCH2ntuiZTpcrPcQvn', 'id': '1aV2jCH2ntuiZTpcrPcQvn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1aV2jCH2ntuiZTpcrPcQvn'}, 'uri': 'spotify:album:1aV2jCH2ntuiZTpcrPcQvn'}, 'popularity': Decimal('44'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Nils Landgren', 'href': 'https://api.spotify.com/v1/artists/6B3ZWSop1mrJd71rwFozVP', 'id': '6B3ZWSop1mrJd71rwFozVP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/6B3ZWSop1mrJd71rwFozVP'}, 'uri': 'spotify:artist:6B3ZWSop1mrJd71rwFozVP'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/5G4mD6dNtV9V30npBbAj0i', 'track_number': Decimal('7'), 'external_urls': {'spotify': 'https://open.spotify.com/track/5G4mD6dNtV9V30npBbAj0i'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/870bf61e6d74ac3c11557bc4cb90a0e38f575669?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '5G4mD6dNtV9V30npBbAj0i', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('349053'), 'external_ids': {'isrc': 'USPRA9900005'}, 'uri': 'spotify:track:5jdyZZl1zFVdzFvN2cWHWE', 'name': 'Street Life', 'album': {'total_tracks': Decimal('11'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b2731f0ff9a82f509cfc550d15dc', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e021f0ff9a82f509cfc550d15dc', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d000048511f0ff9a82f509cfc550d15dc', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'release_date': '1999', 'name': 'The Song Lives On', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/1hRQZQa8ryz2oOunpCMf0Y', 'id': '1hRQZQa8ryz2oOunpCMf0Y', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/1hRQZQa8ryz2oOunpCMf0Y'}, 'uri': 'spotify:album:1hRQZQa8ryz2oOunpCMf0Y'}, 'popularity': Decimal('34'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Lalah Hathaway', 'href': 'https://api.spotify.com/v1/artists/0uNEy4544VZq2KOl7BsLuo', 'id': '0uNEy4544VZq2KOl7BsLuo', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0uNEy4544VZq2KOl7BsLuo'}, 'uri': 'spotify:artist:0uNEy4544VZq2KOl7BsLuo'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/5jdyZZl1zFVdzFvN2cWHWE', 'track_number': Decimal('5'), 'external_urls': {'spotify': 'https://open.spotify.com/track/5jdyZZl1zFVdzFvN2cWHWE'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/d1f1745e941edf1554b8d5e6e3a2362384feeb37?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '5jdyZZl1zFVdzFvN2cWHWE', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('308640'), 'external_ids': {'isrc': 'USWB10000263'}, 'uri': 'spotify:track:6rtGTWFi7HGoK9nCU7gsVA', 'name': 'Leading Me Back to You', 'album': {'total_tracks': Decimal('10'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273b693653b1ee0b7108208a568', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02b693653b1ee0b7108208a568', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851b693653b1ee0b7108208a568', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}], 'release_date': '1989-03-10', 'name': 'Spellbound', 'album_type': 'album', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/7q0WkXf88v6eTtgqrckZHH', 'id': '7q0WkXf88v6eTtgqrckZHH', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/7q0WkXf88v6eTtgqrckZHH'}, 'uri': 'spotify:album:7q0WkXf88v6eTtgqrckZHH'}, 'popularity': Decimal('44'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Michael Franks', 'href': 'https://api.spotify.com/v1/artists/0AVE7rDx4X9w0pW1XlN1om', 'id': '0AVE7rDx4X9w0pW1XlN1om', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/0AVE7rDx4X9w0pW1XlN1om'}, 'uri': 'spotify:artist:0AVE7rDx4X9w0pW1XlN1om'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/6rtGTWFi7HGoK9nCU7gsVA', 'track_number': Decimal('5'), 'external_urls': {'spotify': 'https://open.spotify.com/track/6rtGTWFi7HGoK9nCU7gsVA'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/b7934da9819d134159f3ee9e887e48231c958518?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '6rtGTWFi7HGoK9nCU7gsVA', 'explicit': False, 'type': 'track'}]
10

artist_id가 4H2b90USTVSstPktwUsDZE인것(eq=equal)을 쿼리하고, 인기도가 45이상인 것을 가져오고 싶을때를 가정하여 쿼리를 하면 아래와 같이 코딩하면 된다.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.query(
        KeyConditionExpression=Key('artist_id').eq('4H2b90USTVSstPktwUsDZE'),
        FilterExpression=Attr('popularity').gt(45)
    )
    ## gt = greater than
    ## eq = equal

    print(response['Items'])
    print(len(response['Items']))

    return None

if __name__=='__main__':
    main()

실행결과는 아래와 같다. 필터링해서 2개의 아이템만 가져왔다.

[{'is_playable': True, 'duration_ms': Decimal('233920'), 'external_ids': {'isrc': 'USPRA0600008'}, 'uri': 'spotify:track:0WU4L5lelOjccOeydME65Z', 'name': "Everybody's Talking", 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('48'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0WU4L5lelOjccOeydME65Z', 'track_number': Decimal('8'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0WU4L5lelOjccOeydME65Z'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/3bdbcd65ca07b1f9c93b8a1b7bf0ee3c74026c7b?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0WU4L5lelOjccOeydME65Z', 'explicit': False, 'type': 'track'}, {'is_playable': True, 'duration_ms': Decimal('307333'), 'external_ids': {'isrc': 'USPRA0600004'}, 'uri': 'spotify:track:0g7z3mwBdTn60MIL30TxhZ', 'name': 'Rio De Janeiro Blue', 'album': {'total_tracks': Decimal('13'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b27317d6026f533da4ad42c66663', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e0217d6026f533da4ad42c66663', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d0000485117d6026f533da4ad42c66663', 'height': Decimal('64')}], 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'release_date': '2007', 'name': 'Feeling Good', 'album_type': 'album', 'release_date_precision': 'year', 'href': 'https://api.spotify.com/v1/albums/489jRVamTAWOj7Gj1vFyqn', 'id': '489jRVamTAWOj7Gj1vFyqn', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/489jRVamTAWOj7Gj1vFyqn'}, 'uri': 'spotify:album:489jRVamTAWOj7Gj1vFyqn'}, 'popularity': Decimal('49'), 'artists': [{'name': 'Joe Sample', 'href': 'https://api.spotify.com/v1/artists/4H2b90USTVSstPktwUsDZE', 'id': '4H2b90USTVSstPktwUsDZE', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/4H2b90USTVSstPktwUsDZE'}, 'uri': 'spotify:artist:4H2b90USTVSstPktwUsDZE'}, {'name': 'Randy Crawford', 'href': 'https://api.spotify.com/v1/artists/1twC2fwPG5FkvYcMpVBQRz', 'id': '1twC2fwPG5FkvYcMpVBQRz', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/1twC2fwPG5FkvYcMpVBQRz'}, 'uri': 'spotify:artist:1twC2fwPG5FkvYcMpVBQRz'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/0g7z3mwBdTn60MIL30TxhZ', 'track_number': Decimal('4'), 'external_urls': {'spotify': 'https://open.spotify.com/track/0g7z3mwBdTn60MIL30TxhZ'}, 'artist_id': '4H2b90USTVSstPktwUsDZE', 'preview_url': 'https://p.scdn.co/mp3-preview/2db4951d4ea0d7e870e7001514b9436ddb35d06e?cid=f0cfebcb06b94d84a40ba945f39dab18', 'is_local': False, 'id': '0g7z3mwBdTn60MIL30TxhZ', 'explicit': False, 'type': 'track'}]
2

아니면 아티스트 아이디, 아이디 이런거 모르겠고, popularity가 90이 넘는것만 가져오고 싶다할때 아래와 같이 scan을 이용해서 코딩하면 된다.

import sys
import os
import boto3

from boto3.dynamodb.conditions import Key, Attr

def main():

    try:
        dynamodb = boto3.resource('dynamodb', region_name='ap-northeast-2', endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    except:
        logging.error('could not connect to dynamodb')
        sys.exit(1)

    table = dynamodb.Table('pms-dynamodb-test')
    response = table.scan(FilterExpression=Attr('popularity').gt(90))

    print(response['Items'])
    print(len(response['Items']))

    return None

if __name__=='__main__':
    main()

실행하면 popularity 90이 넘는 아이템 하나를 가져오게 된다.

[{'is_playable': True, 'duration_ms': Decimal('189486'), 'external_ids': {'isrc': 'USUM71913350'}, 'uri': 'spotify:track:2b8fOow8UzyDFAE27YhOZM', 'name': 'Memories', 'album': {'total_tracks': Decimal('1'), 'images': [{'width': Decimal('640'), 'url': 'https://i.scdn.co/image/ab67616d0000b273b8c0135a218de2d10a8435f5', 'height': Decimal('640')}, {'width': Decimal('300'), 'url': 'https://i.scdn.co/image/ab67616d00001e02b8c0135a218de2d10a8435f5', 'height': Decimal('300')}, {'width': Decimal('64'), 'url': 'https://i.scdn.co/image/ab67616d00004851b8c0135a218de2d10a8435f5', 'height': Decimal('64')}], 'artists': [{'name': 'Maroon 5', 'href': 'https://api.spotify.com/v1/artists/04gDigrS5kc9YWfZHwBETP', 'id': '04gDigrS5kc9YWfZHwBETP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/04gDigrS5kc9YWfZHwBETP'}, 'uri': 'spotify:artist:04gDigrS5kc9YWfZHwBETP'}], 'release_date': '2019-09-20', 'name': 'Memories', 'album_type': 'single', 'release_date_precision': 'day', 'href': 'https://api.spotify.com/v1/albums/3nR9B40hYLKLcR0Eph3Goc', 'id': '3nR9B40hYLKLcR0Eph3Goc', 'type': 'album', 'external_urls': {'spotify': 'https://open.spotify.com/album/3nR9B40hYLKLcR0Eph3Goc'}, 'uri': 'spotify:album:3nR9B40hYLKLcR0Eph3Goc'}, 'popularity': Decimal('91'), 'artists': [{'name': 'Maroon 5', 'href': 'https://api.spotify.com/v1/artists/04gDigrS5kc9YWfZHwBETP', 'id': '04gDigrS5kc9YWfZHwBETP', 'type': 'artist', 'external_urls': {'spotify': 'https://open.spotify.com/artist/04gDigrS5kc9YWfZHwBETP'}, 'uri': 'spotify:artist:04gDigrS5kc9YWfZHwBETP'}], 'disc_number': Decimal('1'), 'href': 'https://api.spotify.com/v1/tracks/2b8fOow8UzyDFAE27YhOZM', 'track_number': Decimal('1'), 'external_urls': {'spotify': 'https://open.spotify.com/track/2b8fOow8UzyDFAE27YhOZM'}, 'artist_id': '04gDigrS5kc9YWfZHwBETP', 'preview_url': None, 'is_local': False, 'id': '2b8fOow8UzyDFAE27YhOZM', 'explicit': False, 'type': 'track'}]
1

단 scan을 할때 주의해야할 점이 있다.

key 값을 안쓰는 경우에는 모든 로우를 말그대로 scan하기 때문에 대용량일 경우에는 시간이 매우 소요될 수도 있다.