Google SpreadSheetを元にグラフを描く場合

Google Chart Toolsでグラフを作れるAPIがあるんだけど、そのデータをGoogle SpreadSheetを使って描写が出来るらしい、という事でやってみたら何点かハマったのでメモ。

<html>
  <head>
    <meta charset="UTF-8">
    <title>日本の現状::2013年1月時点</title>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        //SpreadSheet
        var opts = {
          //sendMethod: 'xhr' #無効にする
        };
        var query = new google.visualization.Query(
   'https://spreadsheets.google.com/tq?key=0AqYMJut9ccjYdFBZeFFES1hhOVpVeTN1dm9KMUV3dXc&gid=0',
   opts);
        //URLはhttpsにする。ブラウザーで見ているURLと違うので要注意
        query.setQuery('SELECT A,C,D');
        query.send(handleQueryResponse);
      }

      function handleQueryResponse(response) {
        if (response.isError()) {
          alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
          return;
        }
        var data_query = response.getDataTable();
        var lineChart = new google.visualization.LineChart(document.getElementById('chart_div_age'));
        lineChart.draw(data_query, {title: '年齢(各歳)/男女別人口−総人口(平成23年10月1日現在)'});
      }
</script>
</head>
<body>
<div id="chart_div_age"></div>
</body>
</html>

で間違ったカラム名を変更する方法

class Resource < ActiveRecord::Base
    attr_accessible :resource_id, :type_id, :user_id 
    belongs_to :resource_type

この中のtype_idをbelongs_toのresource_typeのidを紐づけたいと思っていたんだけど、間違ってカラム名をつけてDBに作ってしまった。


↓本当はしたいカラム名(type_id => resource_type_id )

class Resource < ActiveRecord::Base
    attr_accessible :resource_id, :resource_type_id, :user_id 
    belongs_to :resource_type
# $ rails g migration Renameカラム名Toテーブル名 新しいカラム名と型
$ rails g migration RenameTypeToResource resource_type:integer
      invoke  active_record
      create    db/migrate/20130106071025_rename_type_to_resource.rb

生成されたファイルを編集する
↓最初はこんな感じ

class RenameTypeToResource < ActiveRecord::Migration                                                                                                
  def up
  end

  def down
  end
end

↓追記する

class RenameTypeToResource < ActiveRecord::Migration                                                                                                
  def up
    rename_column :resources, :type_id, :resource_type_id
                              #:テーブル名 :古いカラム名 :新しいカラム名
  end

  def down
    rename_column :resources, :resource_type_id, :type_id
                              #:テーブル名 :新しいカラム名 :古いカラム名
  end
end

反映させる

$ rake db:migrate
==  RenameTypeToResource: migrating ===========================================
-- rename_column(:resources, :type_id, :resource_type_id)
   -> 0.0312s
==  RenameTypeToResource: migrated (0.0313s) ==================================

セカンダリー・インデックス

セカンダリー・インデックスとは、MapReduceを活用した追加のインデックス機能である
https://cloudant.com/for-developers/views/

セカンダリー・インデックスは、mapファンクションを利用するして、データをドキュメントから取り出し、reduceファンクションで、データを集約する。

これらのファンクションはJavaScriptで書けるが、専有サービスカスタマーのみしか使えないらしい

プライマリ・インデックス

プライマリ・インデックス機能
#名前の通り

ソート順

順番

#最初に実施されるソートのタイプ
null
false
true

#次の数字
1
10
4.0

#次のテキスト
"a"
#同じ文字であれば小文字一番、大文字二番
"A"
"aa"
"b"
"B"
"ba"
"bb"

#次の配列
["a"]
["b"]
#違う要素と比較されるまでソートされた要素
["b","c"]
["b","c", "a"]
["b","d"]
["b","d", "e"]

#最後にオブジェクト、キー・バリューのリストを違うリストと比較されるまでソートする
{a:1}
{a:2}
{b:1}
{b:2}
{b:2, a:1}
{b:2, c:2}

animaldbドキュメント内容

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs

返却値

{
  "total_rows":11,
  "offset":0,
  "rows":[
    {"id":"_design\/views101","key":"_design\/views101","value":{"rev":"12-dfa39d5771438be0671b9aeb9cfaf03f"}},
    {"id":"aardvark","key":"aardvark","value":{"rev":"3-fe45a3e06244adbe7ba145e74e57aba5"}},
    {"id":"badger","key":"badger","value":{"rev":"4-51aa94e4b0ef37271082033bba52b850"}},
    {"id":"elephant","key":"elephant","value":{"rev":"3-f812228f45b5f4e496250556195372b2"}},
    {"id":"giraffe","key":"giraffe","value":{"rev":"3-7665c3e66315ff40616cceef62886bd8"}},
    {"id":"kookaburra","key":"kookaburra","value":{"rev":"4-6038cf35dfe1211f85484dec951142c7"}},
    {"id":"lemur","key":"lemur","value":{"rev":"3-552d9dbf91fa914a07756e69b9ceaafa"}},
    {"id":"llama","key":"llama","value":{"rev":"4-631ea89ca94b23a3093c1ef7dfce10e0"}},
    {"id":"panda","key":"panda","value":{"rev":"2-f578490963b0bd266f6c5bbf92302977"}},
    {"id":"snipe","key":"snipe","value":{"rev":"3-4b2fb3b7d6a226b13951612d6ca15a6b"}},
    {"id":"zebra","key":"zebra","value":{"rev":"3-750dac460a6cc41e6999f8943b8e603e"}}
  ]
}

検索オプション

limit : 返却値を制限する
skip: 指定の返却値を飛ばす(ページネーションなどに使うとよし)

skip

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs?skip=5

返却値

{
  "total_rows":11,
  "offset":5,
  "rows":[
    {"id":"kookaburra","key":"kookaburra","value":{"rev":"4-6038cf35dfe1211f85484dec951142c7"}},
    {"id":"lemur","key":"lemur","value":{"rev":"3-552d9dbf91fa914a07756e69b9ceaafa"}},
    {"id":"llama","key":"llama","value":{"rev":"4-631ea89ca94b23a3093c1ef7dfce10e0"}},
    {"id":"panda","key":"panda","value":{"rev":"2-f578490963b0bd266f6c5bbf92302977"}},
    {"id":"snipe","key":"snipe","value":{"rev":"3-4b2fb3b7d6a226b13951612d6ca15a6b"}},
    {"id":"zebra","key":"zebra","value":{"rev":"3-750dac460a6cc41e6999f8943b8e603e"}}
  ]
}

limit

$ curl https://{アカウント名}:{パスワード}@{アカウント名.cloudant.com/animaldb/_all_docs?limit=2

返却値

{
  "total_rows":11,
  "offset":0,
  "rows":[
    {"id":"_design\/views101","key":"_design\/views101","value":{"rev":"12-dfa39d5771438be0671b9aeb9cfaf03f"}},
    {"id":"aardvark","key":"aardvark","value":{"rev":"3-fe45a3e06244adbe7ba145e74e57aba5"}}
  ]
}

limit + skip

skip+limitでも同じ結果
&をエスケープする

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs?limit=3\&skip=3

返却値

{
  "total_rows":11,
  "offset":0,
  "rows":[
    {"id":"elephant","key":"elephant","value":{"rev":"3-f812228f45b5f4e496250556195372b2"}},
    {"id":"giraffe","key":"giraffe","value":{"rev":"3-7665c3e66315ff40616cceef62886bd8"}},
    {"id":"kookaburra","key":"kookaburra","value":{"rev":"4-6038cf35dfe1211f85484dec951142c7"}}
  ]
}
startkey(始まりのテキスト) + endkey(終わりのテキスト)

&はエスケープが必要

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs?startkey=\"d\"\&endkey=\"giraffe\"

返却値

{
  "total_rows":11,
  "offset":7,
  "rows":[
    {"id":"elephant","key":"elephant","value":{"rev":"3-f812228f45b5f4e496250556195372b2"}},
    {"id":"giraffe","key":"giraffe","value":{"rev":"3-7665c3e66315ff40616cceef62886bd8"}}
  ]
}
key
$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs?key=\"llama\"

返却値

{
  "total_rows":11,
  "offset":10,
  "rows":[
    {"id":"llama","key":"llama","value":{"rev":"4-631ea89ca94b23a3093c1ef7dfce10e0"}}
  ]
}

一覧

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/llama

返却値

{
  "_id":"llama",
  "_rev":"4-631ea89ca94b23a3093c1ef7dfce10e0",
  "min_weight":130,
  "max_weight":200,
  "min_length":1.6999999999999999556,
  "max_length":1.8000000000000000444,
  "latin_name":"Lama glama",
  "wiki_page":"http:\/\/en.wikipedia.org\/wiki\/Llama",
  "class":"mammal",
  "diet":"herbivore"
}
include_docs

レコード全部を取得する

$ curl https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs?limit=2\&skip=3\&include_docs=true

返却値

{
  "total_rows":11,
  "offset":3,
  "rows":[
    {"id":"elephant","key":"elephant","value":{"rev":"3-f812228f45b5f4e496250556195372b2"},
    "doc":  
      {"_id":"elephant","_rev":"3-f812228f45b5f4e496250556195372b2","wiki_page":"http:\/\/en.wikipedia.org\/wiki\/African_elephant","min_weight":4700,"max_weight":6050,"min_length":3.2000000000000001776,"max_length":4,"class":"mammal","diet":"herbivore"}},
  {"id":"giraffe","key":"giraffe","value":{"rev":"3-7665c3e66315ff40616cceef62886bd8"},
  "doc":
      {"_id":"giraffe","_rev":"3-7665c3e66315ff40616cceef62886bd8","min_weight":830,"min_length":5,"max_weight":1600,"max_length":6,"wiki_page":"http:\/\/en.wikipedia.org\/wiki\/Giraffe","class":"mammal","diet":"herbivore"}
      }
  ]
}
配列をPOSTして抽出する
$ curl -d '{"keys": ["elephant", "snipe", "panda"]}' -X POST https://{アカウント名}:{パスワード}@{アカウント名}.cloudant.com/animaldb/_all_docs -H "Content-Type:application/json"

返却値

{
  "total_rows":11,
  "offset":0,
  "rows":[
    {"id":"elephant","key":"elephant","value":{"rev":"3-f812228f45b5f4e496250556195372b2"}},
    {"id":"snipe","key":"snipe","value":{"rev":"3-4b2fb3b7d6a226b13951612d6ca15a6b"}},
    {"id":"panda","key":"panda","value":{"rev":"2-f578490963b0bd266f6c5bbf92302977"}}
  ]
}

コマンドラインで操作

https://cloudant.com/for-developers/crud/
開発者向けドキュメントを実際にやってみる

ドキュメント内のデータ一覧を見る

$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/_all_docs

データを見てみる(id:1a80cb1cd4b37090afc0f46cdbb43ac4)

$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/1a80cb1cd4b37090afc0f46cdbb43ac4

返却値

{"_id":"1a80cb1cd4b37090afc0f46cdbb43ac4","_rev":"1-85add8f5bff234d37903d156d1285b99","season":"spring","weather":"cool with rain and sun"}

新しくデータを追加する

$ curl -d '{"season": "fall", "weather":"getting cold.."}' -X POST https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ -H "Content-Type:application/json"

返却値

{"ok":true,"id":"ab8ec51de21e46f207c0120096bc8291","rev":"1-7cb081e4a57080cf847230ff99d089e4"}

特定のID(ab8ec51de21e46f207c0120096bc8291)のレコードを取得

$ curl -i -X HEAD https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ab8ec51de21e46f207c0120096bc8291

返却値
E-Tagと上記rev値は同じ

HTTP/1.1 200 OK
X-Couch-Request-ID: bdefc588
Server: CouchDB/1.0.2 (Erlang OTP/R14B)
Etag: "1-7cb081e4a57080cf847230ff99d089e4"
Date: Thu, 03 Jan 2013 07:03:49 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 130
Cache-Control: must-revalidate

特定のIDのレコードを削除

$ curl -i -X DELETE https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ab8ec51de21e46f207c0120096bc8291\?rev\=1-7cb081e4a57080cf847230ff99d089e4

返却値

HTTP/1.1 200 OK
X-Couch-Request-ID: e494b619
Server: CouchDB/1.0.2 (Erlang OTP/R14B)
Etag: "2-3160fe2ec8f2768c6bbe084c6c2b70f7"
Date: Thu, 03 Jan 2013 07:06:53 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 95
Cache-Control: must-revalidate

{"ok":true,"id":"ab8ec51de21e46f207c0120096bc8291","rev":"1-7cb081e4a57080cf847230ff99d089e4"}
もしくはPUTに対して削除するフラグを付ける事で削除が可能
$ curl -d '{"_rev": "1-773b6a59e2f933059c6739df8717b44c", "_deleted":true}' -X PUT https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ab8ec51de21e46f207c0120096bc8291

返却値

{"ok":true,"id":"ab8ec51de21e46f207c0120096bc8291","rev":"1-7cb081e4a57080cf847230ff99d089e4"}

削除されたかどうかの確認(エラー表示)

$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ab8ec51de21e46f207c0120096bc8291
{"error":"not_found","reason":"deleted"}

認証に失敗した時

$ curl https://{アカウント名}.cloudant.com/{ドキュメント名}/ab8ec51de21e46f207c0120096bc8291
{"error":"unauthorized","reason":"_reader access is required for this request"}

一気に追加する

bulk.jsonをファイルで作成する

{"docs":[
    {"name":"document-1"},
    {"name":"document-2"},
    {"name":"document-3"}
  ]}
$ curl -d @bulk.json https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/_bulk_docs -H "Content-Type:application/json"

返却値

[{"id":"32e95e4b33f172f9d03f449223054add","rev":"1-220fa148deee1e7bddb76f9dbfb9e438"},{"id":"32e95e4b33f172f9d03f449223055534","rev":"1-16afea3573a93bc9338ddb43c1ec9491"},{"id":"32e95e4b33f172f9d03f44922305563d","rev":"1-9d9ebabc84a1dd8c7b19f5b3e1feaa24"}]

ファイルの添付方法

どんなタイプのファイルでも添付可能
添付方法

  • inline か standalone

inlineはデータが小さい場合によい
standaloneは、データが大きくて何度も呼び出す場合によい

mime-typeは必須。Content-Typeにて取り扱いする

インラインで追加

※inlineはデータが小さいとはいえ、コマンドラインに全部書くのは大変なので、外部ファイルにすると便利

myphoto.json

{
  "_id":"myprofile",
  "_attachments":
  {
    "myphoto.png":
    {
      "content_type":"image\/png",
      "data": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAABiElEQVQYlQXBzUvbYAAH4N/7sYQkbRpTjGuJzDK/0INYd9hB8Dhhh8EY7DDYceexm7D9CWMH6al3T571IMomePDshlWY7TZs2mLatGls35rk3fOQyNn68mgwKX79sD3a0TX6bbGAo/MzHGSe4I3npdW906yVmTrkakd8HL3btHcK03idtbBWKmLW3sZqL8LYUGBhChAT0NDV/aprAlQRbxdmY0PlsZ0x4lfzbmzOuaI1ZwIPg5BWXqzTT4TgpeWwnELZVe2S3TT+sLDfZ0EsWVRyAHQo/ew4BIaNZ7IH0W2i43fBOUPt1wXuhCBJ0QbQBi+PfPi6ju/9IfzCPDZXTNgsgaYqcINUyl4EAOB3po6kdYMfMwtkVTKiC4HBMJBM19AgkuxuLOF57j04OE3SeAAwK5mEkaxPRkjugX/tFo77URLkDVZZL6cchGa9pyU4rWtlX2M4N1SUrQx+Dw0E1ye8lF8Gv480TsbjGoiKiHVDK/DYzwdHXvz1MEMS5B4X0nqvk0dw2/wPAziepZ5qttMAAAAASUVORK5CYII="
    }
  }
}
$ curl -d @myphoto.json -X POST https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/ -H "Content-Type:application/json

返却値

"{"ok":true,"id":"myprofile","rev":"1-2b0a2ad6d1ba8a4ec811aa67ccb30db1"}
追加されたかどうか再度確認
$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/myprofile

返却値

{"_id":"myprofile","_rev":"1-2b0a2ad6d1ba8a4ec811aa67ccb30db1","_attachments":{"myphoto.png":{"content_type":"image\/png","
revpos":1,"digest":"md5-VY\/bvWh3RCG0BNObBVlMGw==","length":449,"stub":true}}}
バイナリーデータのまま追加する

画像ファイルが例えばtest.pngとすると

$ curl -H "Content-Type: image/png" -X PUT --data-binary @test.png https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/test/picture.png

返却値

{"ok":true,"id":"test","rev":"1-495147af493705593ca20bd47a57f55d"}
||<
確認する
>|sh|
$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/test

返却値

{"_id":"test","_rev":"1-495147af493705593ca20bd47a57f55d","_attachments":{"picture.png":{"content_type":"image\/png","revpos":1,"digest":"md5-JRYzmXDXEIGVhfkHc66+Cg==","length":12799,"stub":true}}}
追加済みのドキュメントに新しく追加する場合

movie.txtをtestドキュメントに追加(PUT)

$ curl -H "Referer: https://{アカウント名}.cloudant.com" -H "Content-Type: text/plain" -X PUT --data-binary @movie.txt https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/test/movie.txt?rev=1-495147af493705593ca20bd47a57f55d

返却値

{"ok":true,"id":"test","rev":"2-2cd8278133b20af9aa974652d08097d1"}

確認

$ curl https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/test

返却値

{
"_id":"test",
"_rev":"2-2cd8278133b20af9aa974652d08097d1",
"_attachments":
   {
   "movie.txt":
      {"content_type":"text\/plain","revpos":2,"digest":"md5-PjtfW8YfeSD1QpOxcPGClA==","length":24,"stub":true},
   "picture.png":
      {"content_type":"image\/png","revpos":1,"digest":"md5-JRYzmXDXEIGVhfkHc66+Cg==","length":12799,"stub":true}
   }
}

movie2.txtをtestドキュメントに追加(POST)

$ curl -H "Referer: https://{アカウント名}.cloudant.com" -H "Content-Type: multipart/form-data" -X POST -F "_attachments=@movie2.txt" -F '_rev=3-94b808999da47c1cc5c360217d8913c8' https://{ユーザー名}:{パスワード}@{アカウント名}.cloudant.com/{ドキュメント名}/test

返却値

{"ok":true,"id":"test","rev":"4-33d32c8f6e0378b3ef9b1ad27c305429"}