FQLのlikeテーブルを扱う時に、本来ならばインデックスできないはずのフィールドをもとに検索できてしまう場合があるという不思議な現象を見つけたので書いておきます。

前提

まず前提ですが、先日和訳したFQLドキュメントにも書かれている通り、FQLではインデックス可能なクエリのみ実行することができます。WHERE句には、各テーブルの定義一覧に指定されているインデックス可能なフィールドを含む必要があります。likeテーブルの場合だと、object_id,post_id,user_idという3つのフィールドのうち、object_idとpost_idがインデックス可能です。

ということは、
SELECT object_id, post_id, user_id FROM like WHERE user_id = me()
のようなクエリを実行して、任意のユーザがlikeした対象を持ってくるという使い方はできず、likeされる対象のid(object_idやpost_id)を軸にして、「誰がlikeしたか」を持ってくるという使い方がこのテーブルの用途となるはずです。ドキュメントにも「任意のFacebookオブジェクト(動画、ノート、リンク、写真、写真アバム)をlikeしたユーザのIDを返します。」と書かれています。

ところが

フォーラムの「ユーザがlikeしたサイトを知るにはどうしたら良いですか」的なトピックにはだいたい、「fql.queryのコンソール画面にSELECT object_id from like WHERE user_id=me()って入力してみれば分かるよ」的な回答があり、それに対して「コンソールだとうまく行ったのに実装したらうまく動かないんだけど」的なリアクションが結構あるようなので、自分でもいろいろと条件を変えて試してみました。

コンソールで試す

fql.queryのコンソール画面
SELECT object_id from like WHERE user_id=me()
を入力して実行します。
ドキュメントの通りだとインデックス不可なのでダメなはずですが、この場合は動作しました。

permission指定なしの場合

    window.fbAsyncInit = function(){
        FB.init({
            appId: XXXXXXXXXXXXXX,
            status: true,
            cookie: true,
            xfbml: true
        });
        FB.api({
            method: 'fql.query',
            query: 'SELECT object_id, post_id, user_id FROM like WHERE user_id = me()'
        },
        function(response){
            alert(response.length);
        });
    };
アプリを作成し、上記コードを実行しました。
動作して、以下のように結果を取得できました。
[
{"object_id":"10150185164311832","post_id":"","user_id":"44007581"},
{"object_id":"132172030190567","post_id":"","user_id":"44007581"},
{"object_id":"751726711921","post_id":"","user_id":"44007581"},
{"object_id":"187472397971615","post_id":"","user_id":"44007581"},
{"object_id":"10150205673342313","post_id":"","user_id":"44007581"},
]

user_likesパーミッションを指定した場合

ユーザのlikeを扱う場合のパーミッションと言えばuser_likesなので、それを指定した状態で試してみます。アプリを別途作成し、下記パーミッションをログインボタンに指定して、ログインした状態で上記と同じjsを実行しました。
<fb:login-button perms="user_likes" />
結果、"statement is not indexable"エラーでした。

それ以外のパーミッションを指定した場合

user_likesの場合だけなのか、それ以外のパーミッションでも同じようにエラーが出るのか分からなかったので、read_streamなど指定して実行してみます。
<fb:login-button perms="read_stream,publish_stream" />
こちらも"statement is not indexable"エラーが出ました。

まとめ

というわけで、extended_permissionsを指定していると動かない様子でした。
  1. フォーラムの回答者はコンソール画面でテストし、それで動作するのでそのまま回答する
  2. 質問者はそれをもとに開発中アプリで実装してみるけど、そちらでは何かしらパーミッション指定しているので"statement is not indexable"エラーが出る
という流れになっているような気がしてきます。
WHERE user_id = ... だとインデックス不可でエラーが出るのが正しいと思うんですが、不思議ですね、、、

追記:

そんなことを週半ばに試していて、週末に記事にまとめようとしたのですが、今日実行してみたら上記全パターンで取得できてしまいました。

それでも、本来ならばWHERE句にインデックス可能なフィールドを含める必要があり、user_idがインデックス不可とされている以上はWHERE user_id = me()で動くのは正しくない気がするので、使わない方が良いんじゃないかという気がしています。