MongoDB-driver-logo
MongoDB 3.0がリリースされ
以前から不評だったJavaDriverも2.xから3.xにメジャーバージョンアップされました。

主な変更点

DB クラス関連が非推奨に

2.x

MongoClient client = new MongoClient();
DB db = client.getDB("hoge");
DBCollection collection = db.getCollection("HogeCollection");

DB クラスではなくMongoDatabaseに。 DBCollectionがMongoCollectioに。

3.x

MongoClient client = new MongoClient();
MongoDatabase db = client.getDatabase("hoge");
MongoCollection collection = db.getCollection("HogeCollection");

当然検索方法も変更に

2.x

DBCursor cursor = collection.find().limit(1000);

3.x

MongoCursor<Document> cursor = collection.find().limit(1000).iterator();

Listへの変換やJson変換の追加

3.xは結果をCursorではなく直接リストへの変換や
ドキュメントをそのままjson文字列に変換することができます。
// to List
List<Document> response = collection.find().limit(maxCount).into(new LinkedList<Document>());

// to JsonString
String docJson = collection.find().first().toJson();

DBObjectからDocumentへ

DBObjectが非推奨になり, Documentが新たに追加。 以前のDBObjectより遥かに書きやすくなりました。

2.x

DBObject doc = new BasicDBObject();
doc.append("a", "MongoDB");
BasicDBList nums = new BasicDBList();
nums.add(1);
nums.add(2)
doc.append("b", nums);

3.x

Document doc = new Document().append("a", "MongoDB")
                .append("b", Arrays.asList(1, 2));

Codecの追加

3.xからオブジェクトのエンコードとデコードを書くことができます。
Codec<T>のインターフェースを実装して設定することができます。
DateではなくZonedDateTime使うときとかこんな感じ。
public class ZonedDateTimeCodec implements Codec<ZonedDateTime> {

    @Override
    public ZonedDateTime decode(BSONReader reader) {
        return Instant.ofEpochSecond(reader.readDateTime()).atZone(ZoneId.systemDefault());
    }

    @Override
    public void encode(BSONWriter bsonWriter, ZonedDateTime value) {
        bsonWriter.writeDateTime(value.toInstant().toEpochMilli());
    }

    @Override
    public Class<ZonedDateTime> getEncoderClass() {
        return ZonedDateTime.class;
    }
}

コレ以外にもORM風に使いこともできる。

対象のクラスを作成。
public class User implements Bson{
    private String id;
    private String name;
    private String surname;

    @Override
    public String toString()
    {
        return new StringBuilder("{ _id : '")
                .append(String.valueOf(id))
                .append("', name : '")
                .append(String.valueOf(name))
                .append("', email : '")
                .append(String.valueOf(email))
                .append("' }").toString();
    }

    public User() {
    }

    public User(String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public String getId()
    {
        return id;
    }

    public void setId(String id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getEmail()
    {
        return email;
    }

    public void setEmail(String email)
    {
        this.email = email;
    }

    @Override
    public <c> BsonDocument toBsonDocument(final Class<c> documentClass, final CodecRegistry codecRegistry) {
        return new BsonDocumentWrapper<user>(this, codecRegistry.get(User.class));
    }
}

次にCodecを作成。

public class UserCodec implements CollectibleCodec<User>
{
    private Codec<Document> documentCodec;

    public UserCodec() {
        this.documentCodec = new DocumentCodec();
    }

    public UserCodec(Codec<Document> codec) {
        this.documentCodec = codec;
    }

    @Override
    public User decode(BsonReader reader,
                       DecoderContext decoderContext)
    {
        Document document = documentCodec.decode(reader,
                                                 decoderContext);

        User user = new User();

        String id = (String) document.get("_id");

        user.setId(id);

        String name = (String) document.get("name");

        user.setName(name);

        String email = (String) document.get("email");

        user.setEmail(email);

        return user;
    }

    @Override
    public void encode(BsonWriter writer,
                       User user,
                       EncoderContext encoderContext)
    {
        Document document = new Document();

        String id = user.getId();
        String name = user.getName();
        String email = user.getEmail();

        if (id != null)
        {
            document.put("_id", id);
        }

        if (name != null)
        {
            document.put("name", name);
        }

        if (email != null)
        {
            document.put("email", email);
        }

        documentCodec.encode(writer, document, encoderContext);
    }

    @Override
    public Class<User> getEncoderClass()
    {
        return User.class;
    }

}

Codecの設定

Codec<Document> defaultDocumentCodec = MongoClient.getDefaultCodecRegistry().get(Document.class);
UserCodec userCodec = new UserCodec(defaultDocumentCodec);
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
    MongoClient.getDefaultCodecRegistry(),
    CodecRegistries.fromCodecs(userCodec)
);

MongoClientOptions options =
    MongoClientOptions.builder()
            .codecRegistry(codecRegistry)
            .build();

MongoClient mongoClient =
    new MongoClient("localhost:27017", options);

作って設定しておけば以下の様な事も可能。

MongoDatabase db =
            mongoClient.getDatabase("hoge");

MongoCollection<User> collection =
    db.getCollection("user", User.class);

User testUser = new User("hogehoge", "hoge@example.com");

// Codec設定済みなのでそのままInsertも可
mongoCollection.insertOne(testUser);

// 取得時も同様に
User firstUser = collection.find().first();

// Cursor取得時に指定クラスへ
MongoCursor<User> cursor = collection.find(User.class).iterator();
結構便利になってますし。
実際に使ってみて2.xより早くなっているので3.xへの移行はおすすめします。
移行のコストはあるものの, 次回のMongoDBのバージョンアップ以降に
2.x系が使えなくなる可能性も大いにあるので, お早めに。

Related Posts