まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:query

Node.js + Express の環境でウェブアプリケーションを開発していると、いくつかの方法で URL のパラメータを受け取る方法があります:
6dnng3pre04xxdebia1g


例えば、 "/xxx?name0=value0&name1=value1" というパス /xxx への GET アクセス時に URL パラメータである name0 及び name1 の値(それぞれ "value0" と "value1" に相当する部分)を取得するには以下のように req.query オブジェクトから取り出すという処理で実現できます:
var express = express();
var app = express();

app.get( '/xxx', function( req, res ){
  var name0 = req.query.name0;
  var name1 = req.query.name1;
    :
});

  :
  :

また、"/yyy/name2" というパスへの GET アクセス時における "name2" 部分を可変にしたい(例えば "/yyy/1" にアクセスした場合は name2 = "1" で、"yyy/2" にアクセスした場合は name2 = "2" として取り出したい)場合は、以下のように req.params オブジェクトから取り出すことで実現できます:
var express = express();
var app = express();

app.get( '/yyy/:name2', function( req, res ){
  var name2 = req.params.name2;
    :
});

  :
  :

ここまでは express の標準機能として実装されています。


で、今回挑戦したいのは "/zzz/name0/name1/name2/.../name9" というパスへの GET アクセス時における name0, name1, name2, ..., name9 の値を取り出すことです。この例ではパラメータが10個ですが、実際にはいくつ存在しているかわからないものとします(1個かもしれないし、10個以上かもしれない)。つまり "/zzz/" で始まるパスへの GET アクセス時に "/zzz" 以降のパス部分をまとめてパラメータ化して取得したい、という要望実現への挑戦です。

パラメータの個数が固定であれば(例えば3つであれば)、上述の "/yyy/:name2" の時の応用で、"/zzz/:name0/:name1/:name2/" のハンドリングを行って、req.params.name0, req.params.name1, req.params.name2 の値をそれぞれ取り出すことで実現できます。ただ今回はこのパラメータの数を可変にしたい場合の実現方法を考えたいのです。

その実現例の1つがこちらです:
var express = express();
var app = express();

app.use( function( req, res, next ){
  if( req.url.startsWith( '/zzz/' ) ){
    // '/zzz/' で始まるパスへのアクセスだった場合は、5文字目以降をパラメータとして取り出し、
// '/zzz?params=' の後ろに URL パラメータとしてくっつけてリダイレクトする var params = req.url.substr( 4 ); res.redirect( '/zzz?params=' + params ); }else{
// '/zzz/' で始まらないパスへのアクセスだった場合はそのまま処理する next(); } });
app.get( '/zzz', function( req, res ){ // params URL パラメータの値を取り出して、'/' で分割する var params = req.query.params.split( '/' );

// params[0] に "name0" が、params[1] に "name1" が、・・それぞれ格納されている : }); : :

可変階層のパスをハンドリングすることはできないので、該当部分を URL パラメータ(params)として処理するようにしています。そして /zzz/ で始まるパスへのアクセスがあった場合は app.use() による前処理として5文字目(2つ目の '/')以降を取り出して params パラメータの値に指定してリダイレクトするようにしています。こうすることで /zzz/name0/name1/name2/../name9 へのアクセスは /zzz?params=name0/name1/../name9 へアクセスするようリダイレクトされ、リダイレクトされた先で元のパラメータを残さず処理することができるようになります。

リダイレクトしての処理なので、ずるい(?)やり方ではあるんですが、一応これなら /zzz/name0/name1/name2/... へのアクセス全般を可変階層でも(リダイレクト先で)処理できそうです。


PHP で MongoDB を使っていると、「その中身を簡単に確認したい!」と思うことがままあります。

MySQL であれば phpMyAdmin など、有名なツールがいくつかありますが、MongoDB の場合は数が限られてい(るように思い)ます。

そんな中で自分が使っているのが phpMoAdmin です。phpMyAdmin と名前が似ていますが、おそらく意識しているのでしょう。

phpMoAdmin はダウンロード&展開するとわかりますが、 moadmin.php という1つの .php ファイルから作られている MongoDB 管理用GUIツールです。ファイル1つなので、このファイルをドキュメントルート以下におくだけで設置完了です。

なお、接続先の MongoDB サーバーの情報もこのファイルの中に直書きします(何も指定しないとローカルホスト状の MongoDB を参照しに行きます)。
例えば MongoDB サーバーがリモートの mongo.test.com というサーバーで、デフォルトの 27017 番ポートで稼働している場合、この moadmin.php ファイルをエディタで開いて 'MONGO_CONNECTION' の値として以下のように記述して保存します:
  define( 'MONGO_CONNECTION', 'mongodb://mongo.test.com:27017' );

これでウェブブラウザからこの moadmin.php を開けば、目的の MongoDB サーバーにアクセスして、コレクションやレコードの状態を参照することができるようになります。


ところで、MongoDB を使っていると大量のデータを扱うことが少なくありません(そのための No-SQL だと思っています)。コレクション(RDB でいう所のテーブル)を指定して、そのレコードの一覧を参照することは簡単ですが、特定の条件を満たすレコードだけを取り出して見ることはできないでしょうか? それが今から紹介するクエリー(Query)機能です。

クエリーを実行するには、コレクションのレコード一覧の画面から "[query]" と書かれた箇所をクリックします:
2014101601

するとクエリーを指定するフィールドが開きます。ここに目的のレコードに絞り込むクエリーを記述して "Query" をクリックすることでレコードを選別することができます。
2014101602


さて、意外と戸惑ったのが、このクエリーの指定方法です。例えば「item_id の値が'14'のレコード」を探したい場合、どのように指定すればいいのでしょうか?意外と資料や情報が少なくて難儀しました。

結論としては CakePHP の find の中で指定するような感覚で、以下のように記載します:
 array('item_id'=>'14')
2014101603

無事見つかりました。同様にして「item_id が '14' で、category_id が '10' のレコード」であればこんな感じになります:
 array('item_id'=>'14','category_id'=>'10')


注意が必要な点として、どうやらこのクエリーで数値を指定する場合、そのデータが数値文字列なのか、数値なのかを意識して指定する必要がありそう、ということです。例えば先程の例を
 array('item_id'=>14)
のように 14 を数値文字列ではなく数値として指定した場合、レコードは見つかりませんでした。
2014101604


要するにデータがどのような型で格納されているのかをちゃんと意識して指定する必要があるのだと思います。

このあたりを気をつけていれば軽量で使える便利なツールといえそうです。


 

このページのトップヘ