Spring Boot で MongoDB をつかってみる

NoSQL 触ったことがなかったので、 Spring Boot で MongoDB を使用してみます。


まずは、ローカル開発は Docker でやるために、Mongo のコンテナを起動します。

というかこの点に関してハマった点をまとめるエントリーです。

まずは、root user および admin database をセットアップせずに起動し、
Application から疎通するために必要な流れをみていきます。

  • docker-compose.yaml
    • MongoDB と mongo-express を記載
    • 初期DBを指定
      • この DB にコレクション(RDBでいう Table のようなイメージ)を作る必要あり
version: '3.1'

services:
  mongo:
    container_name: spring-mongo
    image: mongo:4.2
    restart: always
    environment:
      MONGO_INITDB_DATABASE: spring-mongo
    ports:
      - 27017:27017
    volumes:
      - ./mongo:/data/db
      - ./mongo/init:/docker-entrypoint-initdb.d

  mongo-express:
    container_name: spring-mongo-express
    image: mongo-express
    restart: always
    ports:
      - 9080:8081 # コンテナの 8081 にマッピングしていればホスト側は任意
    depends_on:
      - mongo
spring:
  data:
    mongodb:
      # port: 27017 # if you set not default port

      host: localhost
      database: spring-mongo
      username: demo
      password: 1qazxsw2

host,database,username,password の記載は uri: mongodb://localhost/spring-mongo とすることも可能です。

ここで指定している username,password はどこで設定したかというと、 image: mongo:4.2 の ENTRYPOINT であるdocker-entrypoint.sh にて実行される .js か .sh ファイル にて流し込んでいます。

$ ls -1 mongo/init

01_import_init_data.json
01_import_init_data.sh
02_create_user.js
let user = {
  user: 'demo',
  pwd: '1qazxsw2',
  roles: [{
    role: 'readWrite',
    db: 'spring-mongo'
  }]
};
db.createUser(user);

これで、 docker-compose up -d をすると、

Application の接続先が準備できます。

MongoDB に繋いで確認してみます。 DB,Collection,Document が作成されています。

docker-compose exec  mongo bash

mongo

> show dbs
admin         0.000GB
config        0.000GB
local         0.000GB
spring-mongo  0.000GB

> use spring-mongo
switched to db spring-mongo

> show collections
customer

> db.customer.find()
{ "_id" : ObjectId("6024e6a39c82f64f379738ca"), "firstName" : "Mike", "lastName" : "Popcorn", "_class" : "com.kiyotakeshi.spring.mongo.Customer" }
{ "_id" : ObjectId("6024e6a39c82f64f379738cb"), "firstName" : "Sam", "lastName" : "Smith", "_class" : "com.kiyotakeshi.spring.mongo.Customer" }

これらを接続先として、 application.yaml で指定していたわけです。

あとは、アプリを起動すると...

./mvnw spring-boot:run

MongoDB につなぎこみ、検索できています。

※このアプリの実装はほぼ 参考 記載の Spring のガイドのままです

------------------------------
Customers found with findAll()
2021-02-14 13:30:26.807  INFO 6466 --- [           main] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:12}] to localhost:27017
Customer{id='6024e6a39c82f64f379738ca', firstName='Mike', lastName='Popcorn'}
Customer{id='6024e6a39c82f64f379738cb', firstName='Sam', lastName='Smith'}

--------------------------------
Customer found with findByFirstName('Alice'):
null

--------------------------------
Customers found with findByLastName('Smith'):
Customer{id='6024e6a39c82f64f379738cb', firstName='Sam', lastName='Smith'}
2021-02-14 13:30:26.848  INFO 6466 --- [extShutdownHook] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:3, serverValue:12}] to localhost:27017 because the pool has been closed.

Process finished with exit code 0

root user および admin database をセットアップした場合

以下おまけ。

docker-compose に以下のような記載をしているものを見かけました。

# mongodb
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: 1qazxsw2

# mongo-express
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: 1qazxsw2

これらは、

をしている箇所で、この設定を有効にしている場合、 Application の接続時の設定も変更する必要がありました。

先ほどの設定で、そのままアプリを起動するとコネクション時に認証エラーに。

Caused by: org.springframework.data.mongodb.UncategorizedMongoDbException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='demo', source='spring-mongo', password=<hidden>, mechanismProperties=<hidden>}; nested exception is com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='demo', source='spring-mongo', password=<hidden>, mechanismProperties=<hidden>}

Caused by: com.mongodb.MongoSecurityException: Exception authenticating MongoCredential{mechanism=SCRAM-SHA-1, userName='demo', source='spring-mongo', password=<hidden>, mechanismProperties=<hidden>}

Caused by: com.mongodb.MongoCommandException: Command failed with error 18 (AuthenticationFailed): 'Authentication failed.' on server localhost:27017. The full response is {"ok": 0.0, "errmsg": "Authentication failed.", "code": 18, "codeName": "AuthenticationFailed"}

2021-02-14 13:42:18.968  INFO 6735 --- [           main] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:4}] to localhost:27017 because there was a socket exception raised by this connection.

以下のように、 application.yaml に authentication-database と接続情報を記載する必要があります。

      host: localhost
      database: spring-mongo
      username: root # if you set "MONGO_INITDB_ROOT_USERNAME", change that username
      password: 1qazxsw2
      # if you set "MONGO_INITDB_ROOT_*", in docker-compose
      authentication-database: admin

      # host,database,username,password の記載を一行にまとめる場合
      # uri: mongodb://root:1qazxsw2@localhost/spring-mongo?authSource=admin

これで無事にコネクションできます。