LoginSignup
64
71

More than 5 years have passed since last update.

JavaからMongoDBへのアクセス(接続、検索、insert、update、delete)

Last updated at Posted at 2014-08-07

Java MongoDB Driverを使ってJavaからMongoDBにアクセスする方法について、全くはじめての人向けメモ。
MongoDBには色々機能があるようですが、今回はJava MongoDB Driverを使った簡単なCRUDの記述方法を解説します。

MongoDBのこと

RDBとは用語が異なります。
何も知らずにJava MongoDB Driverのドキュメント読んでも???となってしまうので、最低限、RDBとの用語の違いを把握しておきましょう。

RDBとMongoDBのデータベース構造の比較は以下の通り。

RDB MongoDB
データベース データベース
テーブル コレクション
レコード ドキュメント

また、MongoDBの特徴などは以下のようなサイトで把握します。

build.gradleの設定

build.gradleに以下の設定を追加します

dependencies {
...
    compile group: 'org.mongodb', name:'mongo-java-driver', version:'2.12.3'
...
}

今回はGradleを利用しましたが、自分で依存関係を解決する場合はMongoDB Driversから適切なドライバをダウンロードしてパスを通します。

JavaからMongoDBにアクセス

サーバとの接続・切断

// MongoDBサーバに接続
MongoClient client = new MongoClient("localhost", 27017);
// 利用するDBを取得
DB db = mongoClient.getDB( "mydb" );

...


// サーバから切断
client.close();
  • new MongoClient()でコネクションプールのコネクションを1つをとってくる(らしい)
  • スレッドセーフで、複数のスレッドで共有できるよう設計されているので、1つのアプリで1つのインスタンスでOK(らしい)
  • getDB()したタイミングでデータベースがなければ勝手に生成される

詳しくはGetting Started with Java Driver参照。

認証

セキュアモード(注:Security Tutorials — MongoDB Manual 2.6.3)で起動している場合は認証が必要。

MongoClient mongoClient = new MongoClient();
DB db = mongoClient.getDB("mydb");
boolean auth = db.authenticate(myUserName, myPassword);

コレクション一覧取得

データベース内のコレクション一覧を取得

Set<String> colls = db.getCollectionNames();

for (String s : colls) {
    System.out.println(s);
}

指定のコレクション取得

取得したコレクションに対してCRUD等の操作ができます。

DBCollection coll = db.getCollection("testCollection");

ドキュメントのInsert

取得したコレクションにドキュメントをインサートします。
以下の構造のドキュメントをインサートする場合、

{
   "name" : "MongoDB",
   "type" : "database",
   "count" : 1,
   "info" : {
               "x" : 203,
               "y" : 102
             }
}

Javaのソースは以下になります。

BasicDBObject doc = new BasicDBObject("name", "MongoDB")
        .append("type", "database")
        .append("count", 1)
        .append("info", new BasicDBObject("x", 203).append("y", 102));
coll.insert(doc);

BasicDBObject クラスを使ってデータ構造を作ります。
その後、インサート対象のコレクションのinsert()メソッドを呼び出すだけです。
が、はっきりいってDBObjectを作るのがとてもめんどくさい。。

JSON文字列からDBObjectをつくるには、以下のように記述します。

DBObject json = (DBObject) JSON.parse("{'name':'mkyong', 'age':30}");
coll.insert(json);

ドキュメントの検索

1件目のドキュメントを検索

コレクションから1件だけドキュメントを取得するには、以下のように記述します。

DBObject myDoc = coll.findOne();
System.out.println(myDoc);

カーソルを使って全てのドキュメントを取得

コレクションから全てのドキュメントを取得するにはfind()メソッドを利用します。
find()メソッドでは、クエリに一致した全てのドキュメントにアクセスできます。

DBCursor cursor = coll.find();
try {
   while(cursor.hasNext()) {
       System.out.println(cursor.next());
   }
} finally {
   cursor.close();
}

ドキュメントの件数を取得する

コレクションに何件のドキュメントがあるか調べるにはgetCount()メソッドを利用します。

long count = coll.getCount();
System.out.println(count + "件");

クエリを使って1件のドキュメントを取得する

BasicDBObject query = new BasicDBObject("i", 71);

cursor = coll.find(query);

try {
   while(cursor.hasNext()) {
       System.out.println(cursor.next());
   }
} finally {
   cursor.close();
}

$オペレータを使ったクエリでドキュメントを検索する

MongoDBではクエリに$オペレータを利用して検索や集計等が行えます。
例えば、"qty"フィールドが20でないドキュメントを検索するには以下のように記述します

db.inventory.find( { qty: { $ne: 20 } } )

オペレータについての詳細はOperators — MongoDB Manual 2.6.3 参照。

$オペレータはDBObjectに、通常のStringキーとして設定します。

query = new BasicDBObject("name",                                   
        new BasicDBObject("$ne", "mkyong")).append("count",         
        new BasicDBObject("$gt", 1));                               
cursor = coll.find(query);                                          
try {                                                               
    while (cursor.hasNext()) {                                      
        System.out.println("use $ operrator -> " + cursor.next());  
    }                                                               
} finally {                                                         
    cursor.close();                                                 
}                                                                   

でも、DBObjectを生成するのはやっぱり面倒なので、JSONからクエリを生成します。

json = (DBObject) JSON                                              
        .parse("{'name':{$ne:'mkyong'}, 'count':{$gt:1}}");         
cursor = coll.find(json);                                           
try {                                                               
    while (cursor.hasNext()) {                                      
        System.out.println("use $ ope(JSON) -> " + cursor.next());  
    }                                                               
} finally {                                                         
    cursor.close();                                                 
}                                                                   

coll.remove(new BasicDBObject());                                   

ドキュメントUpdate

ドキュメントを更新するには、更新対象のDBObjectを取得して書き換え、save()メソッドで更新します。
このとき、_idは変更してはいけません。DBObjectの_idが一致するドキュメントがあった場合に上書きされるからです。

doc = coll.findOne();                              
doc.put("name", "MongoDB2"); // name属性を更新       
doc.put("age", "15");        // age属性を追加        
coll.save(doc);                                    

ドキュメントDelete

ドキュメントを削除するには、削除対象のDBObjectを取得して、remove()メソッドで削除します。

doc = coll.findOne();
coll.remove(doc);

コレクション削除

コレクションを削除する場合drop()メソッドを利用します。

System.out.println(db.getCollectionNames()); 
coll.drop();                                           
System.out.println(db.getCollectionNames()); 

サンプルコード

上記の処理まとめ。(認証無し)

MongoClient client = null;                                               

try {                                                                    
    // MondoDBサーバへの接続                                                    
    client = new MongoClient("localhost", 27017);                        
    // client = new MongoClient();                                       
    // 使用するDBの指定                                                         
    DB db = client.getDB("mydb");                                        

    DBCollection coll = db.getCollection("testCollection");              

    // Insert(append版)                                                   
    DBObject doc = new BasicDBObject("name", "MongoDB")                  
            .append("type", "database")                                  
            .append("count", 1)                                          
            .append("info",                                              
                    new BasicDBObject("x", 203).append("y", 102));       
    coll.insert(doc);                                                    

    doc = new BasicDBObject("name", "MongoDB")                           
            .append("type", "database")                                  
            .append("count", 2)                                          
            .append("info",                                              
                    new BasicDBObject("x", 400).append("y", -10));       
    coll.insert(doc);                                                    

    // Insert(JSON版)                                                     
    DBObject json = (DBObject) JSON                                      
            .parse("{'name':'mkyong', 'age':30}");                       
    coll.insert(json);                                                   

    // 1件だけ検索                                                            
    DBObject myDoc = coll.findOne();                                     
    System.out.println("findOne() -> " + myDoc);                         

    // カーソルを使って全件取得                                                      
    DBCursor cursor = coll.find();                                       
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("DBCursor - > " + cursor.next());         
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // ドキュメント件数取得                                                        
    long count = coll.getCount();                                        
    System.out.println(count + "件");                                     

    // クエリを使って1件のドキュメントを取得する                                             
    BasicDBObject query = new BasicDBObject("name", "MongoDB");          
    cursor = coll.find(query);                                           
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("use query -> " + cursor.next());         
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // $オペレータを使ったクエリ                                                     
    query = new BasicDBObject("name",                                    
            new BasicDBObject("$ne", "mkyong")).append("count",          
            new BasicDBObject("$gt", 1));                                
    cursor = coll.find(query);                                           
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("use $ operator -> " + cursor.next());    
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // JSONからクエリを生成                                                      
    json = (DBObject) JSON                                               
            .parse("{'name':{$ne:'mkyong'}, 'count':{$gt:1}}");          
    cursor = coll.find(json);                                            
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("use $ ope(JSON) -> " + cursor.next());   
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // ドキュメントをアップデート                                                     
    doc = coll.findOne();                                                
    doc.put("name", "MongoDB2");    // name属性を更新                         
    doc.put("age", "15");           // age属性を追加                          
    coll.save(doc);                                                      
    cursor = coll.find();                                                
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("updated -> " + cursor.next());           
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // ドキュメントを削除                                                         
    doc = coll.findOne();                                                
    coll.remove(doc);                                                    
    cursor = coll.find();                                                
    try {                                                                
        while (cursor.hasNext()) {                                       
            System.out.println("deleted -> " + cursor.next());           
        }                                                                
    } finally {                                                          
        cursor.close();                                                  
    }                                                                    

    // コレクション削除                                                          
    System.out.println("コレクション削除前: " + db.getCollectionNames());         
    coll.drop();                                                         
    System.out.println("コレクション削除後: " + db.getCollectionNames());         

    coll.remove(new BasicDBObject());                                    

} catch (UnknownHostException e) {                                       
    // TODO Auto-generated catch block                                   
    e.printStackTrace();                                                 
} finally {                                                              
    if (client != null) {                                                
        client.close();                                                  
    }                                                                    
}                                                                        

その他、気になったこと

上記以外に気になって調べたことのメモ。

トランザクション

MongoDBにはトランザクションがなく後勝ちなので、楽観ロックで排他制御するようです。
(4/4)触ってみよう!ビッグデータを支えるクラウド技術 - MongoDBを試してみよう:ITpro参照

(1)クエリーにより、ドキュメントを取り出す。
(2)古い値を保存しておく
(3)ドキュメントを更新
(4)古い値(_idを含む)を第1引数に、新しい更新したドキュメントを第2引数に指定して、updateメソッドを呼ぶ。ドキュメントが書き換わっていたらupdateが失敗する
(5) updateが失敗したら、また(1)からやり直す。

だそうです。

また、一連の操作中にエラーが起きてもその前の処理をロールバックできません。
db.getLastError();メソッドで最後に起こったエラーが確認できるようです。

save()とinsert()、update()の違い

save()メソッドと、insert()、update()メソッドが出てきて使い分けがよくわからなかったのでまとめ。
詳細はjavadoc参照。(DBCollection

save() insert() update()
更新できる件数 1件 1件以上 1件以上(*1)
対象の指定 ドキュメント ドキュメント クエリ
対象レコードの有無等 _idが無ければInsert、あればUpsert - 指定したクエリを発行した時点で取得される_idに対応するドキュメントが、Update実行時コレクションに無い場合は更新失敗*2

*1:updateMulti()メソッドを利用するか、update()メソッドの第4引数にtrueセットで複数件更新。それ以外の場合は最初の1件だけ更新。
*2:update()メソッドの第3引数をtrueに設定するとUpsertされる

Bulkオペレーション

  • 大量のデータを操作する場合はBulkオペレーションを利用すると速いらしい
  • insert/update/removeが一括で処理できる
  • Buklオペレーションには2種類ある
    • Ordered bulk operation:順序を保証
    • Unordered bulk operations:順序を保証しない(並行処理)

StatementのaddBatch()、executeBatch()っぽい。
サンプルコードは以下の通り。

// 1. Ordered bulk operation
BulkWriteOperation builder = coll.initializeOrderedBulkOperation();
builder.insert(new BasicDBObject("_id", 1));
builder.insert(new BasicDBObject("_id", 2));
builder.insert(new BasicDBObject("_id", 3));

builder.find(new BasicDBObject("_id", 1)).updateOne(new BasicDBObject("$set", new BasicDBObject("x", 2)));
builder.find(new BasicDBObject("_id", 2)).removeOne();
builder.find(new BasicDBObject("_id", 3)).replaceOne(new BasicDBObject("_id", 3).append("x", 4));

BulkWriteResult result = builder.execute();

// 2. Unordered bulk operation - no guarantee of order of operation
builder = coll.initializeUnorderedBulkOperation();
builder.find(new BasicDBObject("_id", 1)).removeOne();
builder.find(new BasicDBObject("_id", 2)).removeOne();

result = builder.execute();
64
71
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
64
71