Rails + Couchbaseの組み合わせでデータを扱ってみる

GYAOの窓際エンジニア　玉利です。

社内を歩いていたら「Excel作業トラブルが多いから、新しいチェック作業を追加でお願いする」といういつもの流れをチラリと聞いてしまい、他所の部署の話ながらなんとか低コストで解決してみようと思い立ちました。

簡単な突合の仕組みを実現するのに、Couchbaseにマスタになるデータを置いておき、ビジネス用のRailsアプリから叩いて不整合を自動で検出しようと思います。まだそのアプリは開発中なのですが、こういうのは最初から想定しておかないとダメです。

そんなのSAPとかOracle EBSとかNetsuiteみたいなERP入れちまえば一気に解決するだろ、寄らば大樹の陰だろっていうツッコミが横からくるのですが、私だってベストな方法と思っているわけではありません。

私が師匠と勝手に崇めている、[びーえすでぃー日誌](http://www.bsddiary.net/)のCandy師匠は、「3分節約するために2時間でコードを書くのダ」とおっしゃってたので、チリも積もれば山となると信じましょう。

## やってみる

手元のサーバにRuby on Railsのセットアップしてから、以下のように試す。


Couchbaseのライブラリをインストールできるように、repo情報追加

```
sudo vim /etc/yum.repos.d/couchbase.repo
```

```
[couchbase]
enabled = 1
name = Couchbase package repository
baseurl = http://packages.couchbase.com/rpm/6.2/x86_64
gpgcheck = 1
gpgkey = http://packages.couchbase.com/rpm/couchbase-rpm.key
```

couchbaseライブラリを全部入りで放り込む。

```
sudo yum install libcouchbase-devel libcouchbase2-core libcouchbase2-bin libcouchbase2-libevent libcouchbase2-libev
gem i couchbase
```

これでcouchbaseが利用可能になったはず。
https://github.com/couchbase/couchbase-ruby-client　のユーザーガイドを見ながらすすめる

rails new testapp して、gemfileに以下を追加

```
gem 'couchbase'
bundle install
```

試しにrails consoleから叩いてみる。つながった。

```
[btamari@btamari01 testapp]$ rails c
Loading development environment (Rails 4.2.4)
irb(main):001:0> require 'couchbase'
=> false
irb(main):002:0> c = Couchbase.connect
=> #<Couchbase::Bucket:0x007f9b4ecd76e8 "http://localhost:8091/pools/default/buckets/default/" transcoder=Couchbase::Transcoder::Document, default_flags=0x0, quiet=false, connected=true, timeout=2500000, bootstrap_transport=:http>
```

 デフォルトではdefaultバケットに接続している。get/setができる。ttlでライフタイムも設定可能。

```
c.set("foo", "bar", :flags => 0x1000, :ttl => 30, :format => :plain)
c.set("hoge", "huga", :flags => 0x1000, :ttl => 30, :format => :plain)

irb(main):045:0> c.get("hoge")
=> "huga"
irb(main):046:0> c.get("foo")
=> "bar"
```
 
:ttl => 30を設定したので、30秒待つとデータが消えていて、No Method errorがかえってくる。 すばらしいｗ

以前のワーキングショップで作ったworkバケットに接続。
couchbase consoleのBucketのアコーディオンを開き、[Edit] 画面のpasswordで、認証情報設定（デフォルトはなさ気です）を設定した上でconnectメソッドを叩きます。

```
d = Couchbase.connect(:bucket => "work", :username => "work", :password => "任意パスワード")
d.get("1")
```
 
実行結果
```
irb(main):070:0* d = Couchbase.connect(:bucket => "work", :username => "work", :password => "himitsu")
=> #<Couchbase::Bucket:0x007f9b4f1260f0 "http://localhost:8091/pools/default/buckets/work/" transcoder=Couchbase::Transcoder::Document, default_flags=0x0, quiet=false, connected=true, timeout=2500000, bootstrap_transport=:http>
```

Key = 1 を取得してみます。

```
irb(main):071:0>key1 = d.get("1")
=> {"appKey"=>"MTQyMDAzODkzMg==", "name"=>"えつママ", "gender"=>"2", "prefecture"=>"うどん県", "age"=>"3", "timestamp"=>1420038932, "clubNumber"=>"211671", "comments"=>[{"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}, {"id"=>"208", "comment"=>"健気で優しい歌、ほっこりします。"}, {"id"=>"82", "comment"=>"一番好きなうたです。"}, {"id"=>"53", "comment"=>"なかなかライブでは聴けなくて残念です…(￣▽￣;) メロディーが大好き♪"}, {"id"=>"32", "comment"=>"主人が一番好きな曲です！『神曲だ！』と言ってます(笑)"}]}
```
 
key1の構造を確認する。hashに格納されてます。

```
irb(main):084:0> key1.class
=> Hash
irb(main):094:0> key1.each do |value|
irb(main):095:1* p value
irb(main):096:1> end
["appKey", "MTQyMDAzODkzMg=="]
["name", "えつママ"]
["gender", "2"]
["prefecture", "うどん県"]
["age", "3"]
["timestamp", 1420038932]
["clubNumber", "211671"]
["comments", [{"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}, {"id"=>"208", "comment"=>"健気で優しい歌、ほっこりします。"}, {"id"=>"82", "comment"=>"一番好きなうたです。"}, {"id"=>"53", "comment"=>"なかなかライブでは聴けなくて残念です…(￣▽￣;) メロディーが大好き♪"}, {"id"=>"32", "comment"=>"主人が一番好きな曲です！『神曲だ！』と言ってます(笑)"}]]
=> {"appKey"=>"MTQyMDAzODkzMg==", "name"=>"えつママ", "gender"=>"2", "prefecture"=>"うどん県", "age"=>"3", "timestamp"=>1420038932, "clubNumber"=>"211671", "comments"=>[{"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}, {"id"=>"208", "comment"=>"健気で優しい歌、ほっこりします。"}, {"id"=>"82", "comment"=>"一番好きなうたです。"}, {"id"=>"53", "comment"=>"なかなかライブでは聴けなくて残念です…(￣▽￣;) メロディーが大好き♪"}, {"id"=>"32", "comment"=>"主人が一番好きな曲です！『神曲だ！』と言ってます(笑)"}]}
```
 
 
 
要素は以下のようにhashで取れます。

``` 
irb(main):100:0> print(key1["name"])
えつママ=> nil
irb(main):101:0> print(key1["appKey"])
MTQyMDAzODkzMg===> nil
irb(main):102:0> print(key1["comments"])
[{"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}, {"id"=>"208", "comment"=>"健気で優しい歌、ほっこりします。"}, {"id"=>"82", "comment"=>"一番好きなうたです。"}, {"id"=>"53", "comment"=>"なかなかライブでは聴けなくて残念です…(￣▽￣;) メロディーが大好き♪"}, {"id"=>"32", "comment"=>"主人が一番好きな曲です！『神曲だ！』と言ってます(笑)"}]=> nil
```

問題は、ネストされた先をどう取るか。。。。配列的には8個と出ているので、さらに分解して取り出す必要があります。
Hashで取ったその先は、Arrayでした。

``` 
irb(main):117:0> comments.class
=> Array
 
irb(main):118:0> comments[0]
=> {"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}
```
 
そして、更にその先はHashでした(笑)

```
irb(main):121:0> comment = comments[0]
=> {"id"=>"265", "comment"=>"すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"}
irb(main):122:0> comment.class
=> Hash
 
=> Hash
irb(main):123:0> comment["id"]
=> "265"
irb(main):124:0> comment["comment"]
=> "すごくパワーをもらえる曲です、自分が強くなれたような気持ちになります！"
``` 
 
とりあえず、最低限のKey/Valueが取れるようになったので、実際のデータを突っ込んで行くことにします（つづくかも）

ActiveRecordでがつっと検索したいんだけどな。。。