カテゴリー : MongoDB

[MongoDB] 特定のテキストフィールドが x 文字以上の document を取得する query

MongoDB で特定のテキストフィールドが x 文字以上の document を取得する query をご紹介します。

MongoDB

db.users.find( { name : { $ne: null }, $where: "this.name.length > 5" } )

ポイントは name フィールドに値が存在する場合のみ $where で長さをチェックしている点です。

[MongoDB] MongoError: Runner error: Overflow sort stage buffered data usage of x bytes exceeds internal limit of 33554432 bytes

Express (Node.js) + Mongoose (MongoDB) なアプリケーションで下記のような MongoError: Runner error: Overflow sort stage buffered data usage of 33555427 bytes exceeds internal limit of 33554432 bytes エラーが発生しました。

MongoDB

[ERROR] default - { [MongoError: Runner error: Overflow sort stage buffered data usage of 33555427 bytes exceeds internal limit of 33554432 bytes] name: 'MongoError' }
MongoError: Runner error: Overflow sort stage buffered data usage of 33555427 bytes exceeds internal limit of 33554432 bytes
  at Object.toError (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/utils.js:114:11)
  at /u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:689:54
  at Cursor.close (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:972:5)
  at commandHandler (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/cursor.js:689:21)
  at /u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1847:9
  at Server.Base._callHandler (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:445:41)
  at /u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:478:18
  at [object Object].MongoReply.parseBody (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5)
  at [object Object].<anonymous> (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:436:20)
  at [object Object].EventEmitter.emit (events.js:95:17)
  at [object Object].<anonymous> (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:201:13)
  at [object Object].EventEmitter.emit (events.js:98:17)
  at Socket.<anonymous> (/u/apps/com/shared/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:439:22)
  at Socket.EventEmitter.emit (events.js:95:17)
  at Socket.<anonymous> (_stream_readable.js:746:14)
  at Socket.EventEmitter.emit (events.js:92:17)
  at emitReadable_ (_stream_readable.js:408:10)
  at emitReadable (_stream_readable.js:404:5)
  at readableAddChunk (_stream_readable.js:165:9)
  at Socket.Readable.push (_stream_readable.js:127:10)
  at TCP.onread (net.js:528:21)

sort に指定している field に index を張ってないのが原因でした。

Mongoose の schema 定義に下記のような感じで index 張れば対応完了です。

var User = new Schema({
  created_at: {
    type: Date,
    index: 1
  }
});
 
// or
 
User.index({
  created_at: 1
});

MongoDB に直接 index 張る場合は ensureIndex 使いましょう。

db.users.ensureIndex( { created_at : 1 } )

以上です。

[MongoDB] 改行文字を含む field の値をGoogle スプレッドシートでインポートできる形式で出力する

MongoDB で改行文字を含む field の値を Google スプレッドシートでインポートできる形式で出力する方法をご紹介します。

MongoDB

区切り文字には , (カンマ)を使い、改行文字を含むフィールドを ” (ダブルクオーテーション) で囲みます。

下記の例だと、 detail フィールドが改行文字を含みます。

db.products.find( { detail : regExp } ).forEach(function(p){
  print(p._id.valueOf() + ',"' + p.detail + '"');
});

あとは、スクリプトを実行して、実行結果をファイルに出力して、

mongo --quiet mydb script.js > example.csv

Google スプレッドシートにて、「区切り文字:自動的に検出する」で問題なくインポートできるはずです。

google-spreadsheet-import

以上です。

[MongoDB] クエリ結果を標準出力させてファイルに保存する方法

MongoDB でクエリ結果を標準出力させてファイルに保存するコマンドをご紹介します。

MongoDB

mongo --quiet dbname ./export_users.js > users.tsv

–quiet オプションを付けると、バージョン表示などの余計な情報が出力されなくなります。

ちなみに、export_users.js は下記のような mongo script です。

var users = db.users.find();
 
users.forEach(function(user) {
  if (user) {
    print(user._id + '\t' + user.name + '\t' + user.email);
  }
});

以上です。

[MongoDB] Port を変えて2つ起動する方法 (Mac / Homebrew)

MongoDB を Port を変えて2つ起動する手順 on Mac with Homebrew をご紹介します。

MongoDB

MongoDB の設定(1つ目:ベース)

% cat /usr/local/etc/mongod.conf 
# Store data in /usr/local/var/mongodb instead of the default /data/db
dbpath = /usr/local/var/mongodb
 
# Append logs to /usr/local/var/log/mongodb/mongo.log
logpath = /usr/local/var/log/mongodb/mongo.log
logappend = true
 
# Only accept local connections
bind_ip = 127.0.0.1

MongoDB の設定(2つ目:別 port )

デフォルトは 27017 port で起動しているので、2台目は 27018 port で起動させるように設定していきます。

% mkdir /usr/local/var/mongodb_27018
% cp /usr/local/etc/mongod.conf /usr/local/etc/mongod_27018.conf

mongod_27018.conf を下記のような感じに編集します。

※ dbpath, logpath を編集して、port がデフォルトだと 27017 で重複するので 27018 に変更してます。

% cat /usr/local/etc/mongod_27018.conf
# Store data in /usr/local/var/mongodb instead of the default /data/db
dbpath = /usr/local/var/mongodb_27018
 
# Append logs to /usr/local/var/log/mongodb/mongo.log
logpath = /usr/local/var/log/mongodb/mongo_27018.log
logappend = true
 
# Only accept local connections
bind_ip = 127.0.0.1
 
# Default port: 27017
port = 27018

mongod を起動します。

% mongod run --config /usr/local/etc/mongod_27018.conf &

mongod が別 port で2つ起動していることを確認します。

% lsof -i | grep mongod
mongod      365 bakorer    9u  IPv4 0xd006e2ded5999795      0t0  TCP localhost:28017 (LISTEN)
mongod      365 bakorer   10u  IPv4 0xd006e2deda2a3f7d      0t0  TCP localhost:27017 (LISTEN)
mongod    61419 bakorer    9u  IPv4 0xd006e2dee3ff4795      0t0  TCP localhost:28018 (LISTEN)
mongod    61419 bakorer   10u  IPv4 0xd006e2dee39db795      0t0  TCP localhost:27018 (LISTEN)

以上です。

[MongoDB] 配列フィールドの要素の存在チェック

MongoDB で配列のフィールドに要素が存在するかチェックする条件をご紹介します。

MongoDB

‘arrayFieldName.0’ : { $exists: true } という条件がポイントです。

db.users.find({'friends.0': {$exists: true}})

たまに書くと、「あれ?どう書くんだっけ?」ってなるのですよね。

参考情報

[MongoDB] JavaScript で日付 Date のフォーマット(format)

MongoDB で日付 Date 型を JavaScript で整形するスニペットをご紹介します。

MongoDB

var formatDate = function(date) {
  var y = date.getFullYear();
  var m = date.getMonth() + 1;
  var d = date.getDate();
  var hour = date.getHours();
  var minute = date.getMinutes();
  var second = date.getSeconds();
 
  m = ('0' + m).slice(-2);
  d = ('0' + d).slice(-2);
 
  // フォーマット整形済みの文字列を戻り値にする
  return y + '/' + m + '/' + d + ' ' + hour + ':' + minute + ':' + second;
};
 
var user = db.users.findOne({ _id : ObjectId("5077882d249549a413000279") });
 
var formated_created_at = formatDate(user.created_at);
 
print(formated_created_at);
 
// 出力結果の例
// 2012/05/15 2:38:51

もっと良い方法があったら教えて下さい。

参考情報

[MongoDB] Error: failed to connect to [localhost:27017]

Node.js (Express) + MongoDB という構成のウェブアプリケーション開発でアプリ起動時 (node-dev app.js) に、下記のようなエラーが発生しました。

MongoDB

Webアプリから一切 mongo に接続できなくなりました。CLIからは接続できました。

[ERROR] 21:57:58 Error
Error: failed to connect to [localhost:27017]
    at null.<anonymous> (/Users/bakorer/git/com/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74)
    at EventEmitter.emit (events.js:106:17)
    at null.<anonymous> (/Users/bakorer/git/com/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15)
    at EventEmitter.emit (events.js:98:17)
    at Socket.<anonymous> (/Users/bakorer/git/com/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10)
    at Socket.EventEmitter.emit (events.js:95:17)
    at net.js:830:16
    at process._tickCallback (node.js:415:13)

試行錯誤したものの解決せず、結局、mongodb を再インストールしました。

% brew uninstall mongodb                                             
Uninstalling /usr/local/Cellar/mongodb/2.4.8...
 
% brew install mongodb

インストールにあまり時間が掛からないなら良いんですけど、mongodb はコンパイルに数分ぐらい掛かるので、毎回再インストールするのはちょっとつらいです。

ちなみに、試行錯誤したのは下記のとおりです。

mongod.lock 消して再起動したり、–repair も試してみましたがダメでした。

% ps aux | grep mongo                  
bakorer           572   0.0  0.4  2721360  36264   ??  S    10:00PM   0:00.61 /usr/local/opt/mongodb/mongod run --config /usr/local/etc/mongod.conf
bakorer           896   0.0  0.0  2432784    600 s003  S+   10:04PM   0:00.00 grep mongo
 
% launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
 
% ps aux | grep mongo        
bakorer           982   0.0  0.0  2432784    608 s003  S+   10:07PM   0:00.00 grep mongo
 
% rm /usr/local/var/mongodb/mongod.lock
 
% launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
 
% ps aux | grep mongo                                                
bakorer          1060   0.0  0.0  2432784    604 s003  S+   10:11PM   0:00.00 grep mongo
bakorer          1052   0.0  0.4  2712144  34696   ??  S    10:11PM   0:00.06 /usr/local/opt/mongodb/mongod run --config /usr/local/etc/mongod.conf

解決方法を御存じの方がいらっしゃいましたら、教えて頂けると助かります。

追記: Error: failed to connect to [localhost:27017] 解決しました

未だ解決しておらず、この症状が発生した場合、「システム終了」→「起動」で対応しています。(再起動だとダメ)

無事に解決しました。(2013/12/17)

原因は、アプリケーションから localhost:27017 に繋ぎにいっていたのですが /etc/hosts の中が何も書かれていなかったので localhost に接続できなかったということでした。

アプリケーション側で mongodb への接続設定を書いている箇所を 127.0.0.1 へ変更するか、/etc/hosts を修正するのどちらかで対応可能でした。

hosts file の管理は hoster ってMac用のアプリを使っていたのですが、これが悪さをしていたのかもなのでゴミ箱へダンクシュートしておきました。

[MongoDB] LogLevel(ログレベル)の設定変更方法

MongoDB の LogLevel(ログレベル)の設定を変更する方法をご紹介します。

MongoDB

ログレベルを最高の5に設定する

> use admin
switched to db admin
 
> db.adminCommand({setParameter:1, logLevel:5})
{ "was" : 0, "ok" : 1 }

ログレベルを最低の0に設定する

> db.adminCommand({setParameter:1, logLevel:0})
{ "was" : 5, "ok" : 1 }

ログレベルを上げると log ファイルのサイズがめっちゃ大きくなってディスクの容量を食うので、ログの調査などが終わったら適切なログレベルに戻すことをお忘れなく。

参考情報

[MongoDB] バックアップ mongodump とリストア mongorestore

MongoDB のバックアップ mongodump とリストア mongorestore の方法をご紹介します。

MongoDB

mongodump でバックアップ

localhost の test_db をバックアップする。

mongodump --host localhost --db test_db

localhost の test_db にある test_collection をバックアップする。

mongodump --host localhost --db test_db --collection test_collection

mongorestore でリストア

バックアップした test_db を全てリストアする。

mongorestore --host localhost --db test_db ./dump/test_db

バックアップした test_db の test_collection をリストアする。

mongorestore --host localhost --db test_db --collection test_collection  ./dump/test_db/test_collection.bson

以上です。