MongoDB 2.0.0 Driver 사이트의 Driver CRUD Operations document의 번역 자료입니다. 번역에 문제가 있다면 댓글 달아주시구요. 원문을 보시기를 추천드립니다.

Tutorial Contents

Driver CRUD Operations

드라이버 CRUD operation은 document를 insert/update/remove 및 query를 위해 수행되는 operation으로 정의됩니다. 이 튜토리얼에서는 기본 CRUD 메서드와 특수한 findAndModify 베이스의 메서드와 효율적인 bulk write operation을 허용하는 새로운 Bulk API 메서드를 모두 다룹니다. 그러나 collection class에있는 insert, update and remove operation에 대한 간단한 소개부터 시작합니다.

Write Methods

Inserting Documents

insertOneinsertMany 메서드는 Collection 클래스에 있으며 MongoDB에 document를 삽입하는 데 사용됩니다. 코드는 천 단어(thousand words)로 말하므로 document를 insert 하는 간단한 두 가지 예를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  // Insert a single document
  db.collection('inserts').insertOne({a:1}, function(err, r) {
    assert.equal(null, err);
    assert.equal(1, r.insertedCount);

    // Insert multiple documents
    db.collection('inserts').insertMany([{a:2}, {a:3}], function(err, r) {
      assert.equal(null, err);
      assert.equal(2, r.insertedCount);

      db.close();
    });
  });
});

첫 번째 insert는 단일 document를 inserts collection에 insert합니다. 서버가 첫 번째 document를 insert 할 때 암시적(implicitly)으로 새 insert collection을 생성하므로 명시적(explicitly)으로 새 inserts collection을 작성하지 않습니다. db.createIndex 메서드는 capped collection과 같은 비표준(non standard) collection을 만들거나 기본 collection 이외의 다른 매개 변수를 적용해야하는 경우에만 사용해야합니다.

insertOneinsertMany 메서드는 옵션 object가 될 수있는 두 번째 인수도 허용합니다. 이 object는 다음 필드를 가질 수 있습니다.

  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0}은 write concern이 완료되기를 기다리는 시간 제한을 설정합니다 (w 옵션과 결합).
  • j, (Boolean, default : false) write가 journal sync를 기다립니다.
  • serializeFunctions, (Boolean, default : false) object의 함수를 mongodb로 직렬화(serialize)합니다. 기본적으로 드라이버는 전달 된 document의 함수를 직렬화하지 않습니다.
  • forceServerObjectId, (Boolean, default:false) 서버가 드라이버 대신 _id 값을 할당하도록 합니다.

replicaset에 write하는 간단한 예제를 살펴보고 전달 된 함수를 직렬화(serialize)하고 서버가 각 document에 _id를 할당하도록 하겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  // Insert a single document
  db.collection('inserts').insertOne({
        a:1
      , b: function() { return 'hello'; }
    }, {
        w: 'majority'
      , wtimeout: 10000
      , serializeFunctions: true
      , forceServerObjectId: true
    }, function(err, r) {
    	assert.equal(null, err);
    	assert.equal(1, r.insertedCount);
    	db.close();
  });
});

insert 메서드를 마무리합니다. 다음으로 update 메서드를 살펴 보겠습니다.

Updating Documents

updateOneupdateMany 메서드는 Collection 클래스에 있으며 document를 MongoDB로 업데이트하고 업로드하는 데 사용됩니다. 몇 가지 사용 예를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('updates');
  // Insert a single document
  col.insertMany([{a:1}, {a:2}, {a:2}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Update a single document
    col.updateOne({a:1}, {$set: {b: 1}}, function(err, r) {
      assert.equal(null, err);
      assert.equal(1, r.matchedCount);
      assert.equal(1, r.modifiedCount);

      // Update multiple documents
      col.updateMany({a:2}, {$set: {b: 1}}, function(err, r) {
        assert.equal(null, err);
        assert.equal(2, r.matchedCount);
        assert.equal(2, r.modifiedCount);

        // Upsert a single document
        col.updateOne({a:3}, {$set: {b: 1}}, {
          upsert: true
        }, function(err, r) {
          assert.equal(null, err);
          assert.equal(0, r.matchedCount);
          assert.equal(1, r.upsertedCount);
          db.close();
        });
      });
    });
  });
});

update 메서드는 옵션 object가 될 수있는 두 번째 인수도 허용합니다. 이 객체는 다음 필드를 가질 수 있습니다.

  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0}은 write concern이 완료되기를 기다리는 시간 제한을 설정합니다 (w 옵션과 결합).
  • j, (Boolean, default:false) write가 journal sync를 기다립니다.
  • multi, (Boolean, default:false) 작업으로 one/all document를 업데이트합니다.
  • upsert, (Boolean, default:false) update operation이 upsert입니다.

update 메서드를 insert처럼 w, wtimeoutfsync 파리미터를 사용하여 작업별 write concern을 지정할 수 있습니다

Removing Documents

deleteOnedeleteMany 메서드는 Collection 클래스에 있으며 MongoDB에서 document를 remove하는 데 사용됩니다. 몇 가지 사용 예를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('removes');
  // Insert a single document
  col.insertMany([{a:1}, {a:2}, {a:2}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Update a single document
    col.deleteOne({a:1}
      , {$set: {b: 1}}, function(err, r) {
      assert.equal(null, err);
      assert.equal(1, r.deletedCount);

      // Update multiple documents
      col.deleteMany({a:2}
        , {$set: {b: 1}}, function(err, r) {
        assert.equal(null, err);
        assert.equal(2, r.deletedCount);
        db.close();
      });
    });
  });
});

deleteOnedeleteMany 메서드는 옵션 object가 될 수있는 두 번째 인수도 허용합니다. 이 object는 다음 필드를 가질 수 있습니다.

  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0}은 write concern이 완료되기를 기다리는 시간 제한을 설정합니다 (w 옵션과 결합).
  • j, (Boolean, default:false) write가 journal sync를 기다립니다.
  • single, (Boolean, default:false) 발견된 첫 번째 document를 제거합니다.

updateOne/updateManyinsertOne/insertMany와 마찬가지로 deleteOne/deleteMany 메서드를 사용하면 w, wtimeoutfsync 매개 변수를 사용하여 작업 별 write concern을 지정할 수 있습니다.

findAndModify and findAndDelete

findOneAndUpdate, findOneAndDeletefindOneAndReplace의 두 가지 메서드는 사용자가 document를 update 또는 upsert 하고 수정 또는 기존 document를 리턴 할 수있는 special commands입니다. 수정(modification)이 원자성(atomic)을 보장해야하기 때문에 작업 시간 동안 작업이 쓰기 잠금(write lock)을 수행하므로 비용이 발생합니다. 먼저 예제를 사용하여 findOneAndUpdate를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('findAndModify');
  // Insert a single document
  col.insert([{a:1}, {a:2}, {a:2}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.result.n);

    // Modify and return the modified document
    col.findOneAndUpdate({a:1}, {$set: {b: 1}}, {
        returnOriginal: false
      , sort: [[a,1]]
      , upsert: true
    }, function(err, doc) {
      assert.equal(null, err);
      assert.equal(1, r.value.b);

      // Remove and return a document
      col.findOneAndDelete({a:2}, function(err, r) {
        assert.equal(null, err);
        assert.ok(r.value.b == null);
        db.close();
      });
    });
  });
});

findOneAndUpdate 메서드는 옵션 object가 될 수있는 두 번째 인수도 허용합니다. 이 객체는 다음 필드를 가질 수 있습니다.

  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0} 은 write concern의 완료를 기다리는 시간 제한 설정합니다. (w 옵션과 결합).
  • j, (Boolean, default : false) write가 저널 동기화(journal sync)를 기다립니다.
  • upsert, (Boolean, default:false) upsert 작업을 수행합니다.
  • sort, (Object, default:null) find operation을 위해 정렬
  • projection, (Object, default:null) 반환 된 결과에 대한 projection
  • returnOriginal, (Boolean, default:true) 원본이 아닌 수정 된 object를 반환하려면 false로 설정하십시오. remove 무시

findAndDelete 함수는 document를 remove 할 수 있도록 특별히 정의 된(especially defined) 함수입니다. 사용법의 예를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('findAndModify');
  // Insert a single document
  col.insert([{a:1}, {a:2}, {a:2}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.result.n);

    // Remove a document from MongoDB and return it
    col.findOneAndRemove({a:1}, {
        sort: [[a,1]]
      }
      , function(err, doc) {
        assert.equal(null, err);
        assert.ok(r.value.b == null);
        db.close();
    });
  });
});

findOneAndUpdate와 마찬가지로 다음과 같은 필드를 가질 수있는 옵션 object를 전달할 수 있습니다.

  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0}은 write concern이 완료되기를 기다리는 시간 제한을 설정합니다 (w 옵션과 결합).
  • j, (Boolean, 기본값 : false) write가 저널 동기화(journal sync)를 기다립니다.
  • sort, (Object, default : null) find operation을 위해 정렬합니다.

BulkWrite

bulkWrite 함수를 사용하면 다음에 설명하는 bulk API와 비교하여 간단한 bulk 작업 셋(set of bulk)을 유창하지(fluent) 않은 방식으로 수행 할 수 있습니다. 예를 봅시다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  // Get the collection
  var col = db.collection('bulk_write');
  col.bulkWrite([
      { insertOne: { document: { a: 1 } } }
    , { updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
    , { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
    , { deleteOne: { filter: {c:1} } }
    , { deleteMany: { filter: {c:1} } }
    , { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}]
  , {ordered:true, w:1}, function(err, r) {
    assert.equal(null, err);
    assert.equal(1, r.insertedCount);
    assert.equal(1, Object.keys(r.insertedIds).length);
    assert.equal(1, r.matchedCount);
    assert.equal(0, r.modifiedCount);
    assert.equal(0, r.deletedCount);
    assert.equal(2, r.upsertedCount);
    assert.equal(2, Object.keys(r.upsertedIds).length);

    // Ordered bulk operation
    db.close();
  });
});

보시다시피 bulkWrite 함수는 insertOne, insertMany, updateOne, updateMany, deleteOne 또는 deleteMany의 객체가 될 수있는 operation 배열을 취합니다. 또한 다음 옵션을 취하는 두 번째 매개 변수가 필요합니다.

  • ordered, (Boolean, default : true) 순서대로 또는 순서대로 실행합니다.
  • w, {Number/String, > -1 || ‘majority’}는 {ok:1} 결과가 아닌 write의 승인을 리턴하는 where < 1 operation 그리고 w >= 1 또는 w = ‘majority’ 의 전체 쓰기 결과(full write results)의 write를 승인하는 응답을 위한 write concern(쓰기 고려)
  • wtimeout, {Number, 0}은 쓰기 문제가 완료되기를 기다리는 시간 제한을 설정합니다 (w 옵션과 결합).
  • j, (Boolean, default:false) write가 저널 동기화(journal sync)를 기다립니다.

기본적인 쓰기 작업을 다룹니다. 다음으로 대량 쓰기 작업을 살펴 보겠습니다.

Bulk Write Operations

bulk write operation을 통해 operation 그룹을 MongoDB에 쉽게 write할 수 있습니다. 새로운 write commands을 지원하는 MongoDB 2.6 이상에서 실행하는 데 필요한 다소의 주의 사항과 최상의 성능을 얻을 수 있습니다. 대량 작업은 ordered bulk operation과 unordered bulk operation으로 나뉩니다. ordered bulk operation은 쓰기 실행 순서를 보장하는 반면, unordered bulk operation은 실행 순서에 대한 가정을 하지 않습니다(no assumptions). Node.js 드라이버에서 unordered bulk operation 은 유형에 따라 operation을 그룹화하고 병렬(parallel)로 작성합니다. 주문 대량 작업을 작성하는 방법을 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('bulkops');
  // Create ordered bulk, for unordered initializeUnorderedBulkOp()
  var bulk = col.initializeOrderedBulkOp();
  // Insert 10 documents
  for(var i = 0; i < 10; i++) {
    bulk.insert({a: i});
  }

  // Next perform some upserts
  for(var i = 0; i < 10; i++) {
    bulk.find({b:i}).upsert().updateOne({b:1});
  }

  // Finally perform a remove operation
  bulk.find({b:1}).deleteOne();

  // Execute the bulk with a journal write concern
  bulk.execute(function(err, result) {
    assert.equal(null, err);
    db.close();
  });
});

드라이버 API에 문서화(documented) 된 결과 object는 여기에서 다루지 않습니다. Bulk API는 모든 operation 분할을 multiple write로 처리하고 2.4 이전 서버의 2.6 이상 write명령을 에뮬레이션합니다.

Bulk API 와 특히 ordered bulk API 모드를 사용할 때 명심해야 할 중요한 사항이 있습니다. write command는 single operation 타입입니다. 즉,insert/update 및 remove 만 수행 할 수 있습니다. f.ex 인 경우 다음 operation 조합을 수행하십시오.

Insert {a:1}
Update {a:1} to {a:1, b:1}
Insert {a:2}
Remove {b:1}
Insert {a:3}

이로 인해 드라이버는 서버에 4 개의 write command를 발행(issuing)하게 됩니다.

Insert Command with {a:1}
Update Command {a:1} to {a:1, b:1}
Insert Command with {a:2}
Remove Command with {b:1}
Insert Command with {a:3}

대신 다음과 같은 방법으로 ordered를 구성하십시오.

Insert {a:1}
Insert {a:2}
Insert {a:3}
Update {a:1} to {a:1, b:1}
Remove {b:1}

드라이버가 발행(issued) 한 쓰기 명령의 수입니다.

Insert Command with {a:1}, {a:2}, {a:3}
Update Command {a:1} to {a:1, b:1}
Remove Command with {b:1}

보다 효율적이고 빠른 bulk write operation이 가능합니다.

unordered bulk operation의 경우 드라이버가 타입별로 operation을 정렬하고 병렬로 실행하므로 중요하지 않습니다.

여기에는 MongoDB의 write operation이 포함됩니다. 다음에 document 쿼리를 살펴 보겠습니다.

Read Methods

데이터베이스에 쿼리하는 주요 방법은 findaggregate입니다. aggregateAggregation Tutorial 이 있으므로 본 CRUD 튜토리얼 에서는 find에만 중점을 둡니다.

이 메서드서드는 데이터를 조작 할 수있는 커서를 반환합니다. 또한 커서는 Node.js 0.10.x 이상의 스트림 인터페이스를 구현하여 결과를 다른 스트림으로 pipe 할 수 있습니다. Streams Tutorial에서 다루는 스트림은 여기에서 다루지 않습니다.

toArray를 사용하여 쿼리의 모든 document를 구체화(materialize)하지만 반환 된 결과 수를 2 개의 document로 제한하는 간단한 find 예제를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('find');
  // Insert a single document
  col.insertMany([{a:1}, {a:1}, {a:1}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Get first two documents that match the query
    col.find({a:1}).limit(2).toArray(function(err, docs) {
      assert.equal(null, err);
      assert.equal(2, docs.length);
      db.close();
    });
  });
});

find 메서드가 리턴 한 커서에는 query 옵션을 체인으로 연결할 수있는 많은 메서드가 있습니다. 쿼리를 실행할 준비가되면 next, eachtoArray 메서드를 사용하여 document를 검색(retrieve) 할 수 있습니다. 쿼리가 많은 document를 반환하는 경우 toArray 메서드는 쿼리가 많은 documents를 반환하는 경우 많은 메모리를 사용하여 콜백 함수를 호출하기 전에 모든 document를 메모리에 구체화하기(materialize) 때문에 next 또는 each 메서드를 사용하는 것이 좋습니다.

Cursor API documentation에서 볼 수있는 커서에서 설정할 수있는 옵션은 살펴 보지 않습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('find');
  // Insert a single document
  col.insertMany([{a:1}, {a:1}, {a:1}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Get first documents from cursor
    col.find({a:1}).limit(2).next(function(err, doc) {
      assert.equal(null, err);
      assert.ok(doc != null);
      db.close();
    });
  });
});

next method는 애플리케이션이 콜백을 사용하여 한 번에 하나의 document를 읽을 수 있도록 합니다. 다음에 each 메서드를 살펴 보겠습니다.

var MongoClient = require('mongodb').MongoClient
  , assert = require('assert');

// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
  assert.equal(null, err);
  console.log("Connected correctly to server");

  var col = db.collection('find');
  // Insert a single document
  col.insertMany([{a:1}, {a:1}, {a:1}], function(err, r) {
    assert.equal(null, err);
    assert.equal(3, r.insertedCount);

    // Get first documents from cursor using each
    col.find({a:1}).limit(2).each(function(err, doc) {
      if(doc) {
        db.close();
        // Got a document, terminate the each
        return false;
      }
    });
  });
});

each 메서드는 쿼리를 만족하는 document가 더 이상 없을 때까지 제공된 콜백을 호출합니다. 사용 가능한 document가 소진(exhausted)되면 콜백의 두 번째 매개 변수에 대해 null을 반환합니다. each를 조기에 종료하려면 each 콜백에서 false를 반환해야합니다. 커서가 document를 반환하지 않습니다.

Node.js MongoDB 드라이버의 기본 CRUD operation을 다룹니다.