Node.jsにおけるMongoDB Driverで、MongoDBにアクセス

以前の投稿で、MongooseでMongoDBにアクセスする方法を検証した。本投稿では、本家が公開しているNode.js用の純正ドライバの使い方に関するメモになる。

そもそもなぜネイティブドライバを検証したかというと、同一コレクション内に複数のスキーマドキュメントがあり、それぞれのドキュメントにアクセスしようとしたところ、Override errorが出た。どうもMongooseでは、同一コレクションに異なるスキーマを生成することを許可してないらしい。

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var schema1 = Schema( { name:String } );
var schema2 = Schema( { name:String, age:Number } );
 
var model1 = mongoose.model('col', schema1);
var model2 = mongoose.model('col', schema2);

model2を取得しようとすると、エラーが発生する。最初はそんなはずでは?といろいろ調べたが、同じようなことをやろうとしている情報がみつからず、解決に至ってない。

筆者がやろうとしていることは、1つのコレクション内に複数のスキーマをもつドキュメントを詰めたいので、上記のようにモデルが作成できないと、実現できない。なんとなくMongooseは、「NOSQLであるMongoDBをRDBMSのように使うモジュール」という印象を受けた。それを望んでいるのであれば、Mongooseを使えば良い。

素直にコレクションを分ければ良い話だが、RDBMSの窮屈さがちょっと嫌で、MongoDBのゆるさに期待していたのに、Mongooseにあわせたモデル設計ってのはなんだか違う気がするので、純正のドライバを試してみようと思ったわけである。

基本的MongoDBドライバは、mongoコンソールから実行するコマンドに準拠している。
オンラインヘルプ:http://mongodb.github.io/node-mongodb-native/

ざっくりとだが、基本的なアクセス方法を下記にまとめた。

データの参照(find)

localhostのtestデータベースにアクセスする。コレクションpersonsに対し、nametaroのドキュメントを出力する

var mongo = require('mongodb');
var test = require('assert');
 
mongo.MongoClient.connect( 'mongodb://localhost/test', function( err, db ){
  test.equal(null,err); 
  var collection = db.collection('persons');
  // query
  collection.find( {"name":"taro"} ).toArray( function( err, docs ){
    docs.forEach( function( doc ){
      // output document
      console.log( JSON.stringify( doc ) );
    });
    db.on('close', function() {
      console.log( "@db closed.");
    });
    db.close();
  });
});

ページング( sort, limit, skip )

findを実行すると、Cursorクラスのインスタンスが結果として返される。Cursorクラスのメソッドにsortlimitなどのフィルタ関数がある。

下記のようにsort, limit, skipを実行することによって、ページングすることができる。下記の場合、genderageでソートし、一つ目のドキュメントをスキップして、最大2件のドキュメントを返す。

collection.find( {} ).sort( [{"gender":1},{"age":-1}] )
    .limit(2).skip(1).toArray( function( err, docs ){
      docs.forEach( function( doc ){
        // docが2件取得される
      });
});

データの追加(insertOne)

nameがryoのドキュメントを追加する。まとめて複数のドキュメントを追加するinsertManyという関数もある。

var mongo = require('mongodb');
var test = require('assert');
 
mongo.MongoClient.connect( 'mongodb://localhost/test', function( err, db ){
  test.equal(null,err); 
  var collection = db.collection('persons');
  // insert
  collection.insertOne(
    {"name":"ryo", "age":34,"children":["aa","bb"],"job":{"name":"ZZZ co.","category":"operator"}},
    {}, function(error, result){
     
    console.log(JSON.stringify(result));
    db.on('close', function() {
      console.log( "@db closed.");
    });
    db.close();
  });
});

データの更新(findOneAndUpdate)

nameがryoのドキュメントを更新する。
mongoコンソールと同じように$set,$unset,$push,$pushAll,$pull,$pullAll...etcが使える。

var mongo = require('mongodb');
var test = require('assert');
 
mongo.MongoClient.connect( 'mongodb://localhost/test', function( err, db ){
  test.equal(null,err); 
  var collection = db.collection('persons');
  // update
  collection.findOneAndUpdate(
    { "name":"ryo"}, 
    { $set : {"age":43,"job.category":"manager"}, $pushAll :{"children":["666","777"]} }, 
    {}, function(error, result){
     
    console.log(JSON.stringify(result));
     
    db.on('close', function() {
      console.log( "@db closed.");
    });
    db.close();
  });
});

データの削除(deleteOne)

nameがryoのドキュメントを削除する。

var mongo = require('mongodb');
var test = require('assert');
 
mongo.MongoClient.connect( 'mongodb://localhost/test', function( err, db ){
  test.equal(null,err); 
  var collection = db.collection('persons');
  // delete
  collection.deleteOne(
    { "name":"ryo" }, 
    {}, function(error, result){
     
    console.log(JSON.stringify(result));
     
    db.on('close', function() {
      console.log( "@db closed.");
    });
    db.close();
  });
});

重複を除外したフィールド値を取得(distinct)

genderがmかfのnameを重複除去して取得する。結果は配列で取得される。

var mongo = require('mongodb');
var test = require('assert');
 
mongo.MongoClient.connect( 'mongodb://localhost/test', function( err, db ){
  test.equal(null,err); 
  var collection = db.collection('persons');
  // distinct
  collection.distinct(
    "name",
    { $or : [{ "gender":"m" },{ "gender":"f" }]}, 
    {}, function(error, array){
     
    // ["taro", "ken", "hanako"]
    console.log(array);
     
    db.on('close', function() {
      console.log( "@db closed.");
    });
    db.close();
  });
});

mongoコンソールの操作とほとんど同じ感覚の操作になる