MongoDBの導入手順は以下の記事に記述しています。
JavaでMongoDBを操作する(SpringBoot)
依存関係の追加
build.gradleにspring-boot-starter-data-mongodb
の依存関係を追加する。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
}
接続先設定
application.ymlでDBの接続先などを定義する。
spring: data: mongodb: host: localhost port: 27017 database: Sample username: aa001 password: aa001
エンティティの作成
@Document
のcollection属性に、エンティティが対応するコレクション名を指定する。- 引数なしコンストラクタは内部の処理で必要なので、引数ありコンストラクタを定義している場合は明示的に宣言する。
_id
カラムに対応するフィールドには@Id
を付与する。
import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "Customer") public class Customer { /** id */ @Id public String id; /** 名 */ public String firstName; /** 姓 */ public String lastName; /** * コンストラクタ。<br> */ public Customer() { } /** * コンストラクタ。<br> * * @param firstName * 名 * @param lastName * 姓 */ public Customer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } /** * コンストラクタ。<br> * * @param id * ID * @param firstName * 名 * @param lastName * 姓 */ public Customer(String id, String firstName, String lastName) { this.id = id; this.firstName = firstName; this.lastName = lastName; } /** * 名を取得する。<br> * * @return 名 */ public String getFirstName() { return firstName; } /** * 名を設定する。<br> * * @param firstName * 名 */ public void setFirstName(String firstName) { this.firstName = firstName; } @Override public String toString() { return String.format( "Customer[id=%s, firstName='%s', lastName='%s']", id, firstName, lastName); } }
Repositoryの作成
MongoRepositoryには基本的なCRUDメソッドが用意されているが、必要であれば独自のメソッドを定義することができる。
import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Repository; @Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public Customer findByFirstName(String firstName); public List<Customer> findByLastName(String lastName); }
独自定義のメソッドのキーワードについて
公式ドキュメントに詳しい説明がある。
使用できるキーワードの一覧はここのページ参照。
独自定義のメソッドの引数には基本型以外にも任意の型を指定することができる。
独自定義の検索メソッドにおいて、戻り値がIterableでない際に検索結果として複数件得られた場合、IncorrectResultSizeDataAccessException
がスローされる。
@Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public Customer findByCustomerSearchParam(CustomerSearchParam searchParam); }
メソッド名に「First」キーワードがある場合は、検索結果として複数件得られた場合最初の1件が取得される。
@Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public Customer findFirstByCustomerSearchParam(CustomerSearchParam searchParam); }
複数カラムで検索する場合は「And」もしくは「Or」キーワードを使用する。
@Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public Customer findByLastNameAndAge(String lastName, int age); }
独自定義のメソッドにページャーを適用する場合は、メソッドの引数にorg.springframework.data.domain.Pageable
を追加する。
@Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public List<Customer> findByLastName(String lastName, Pageable pageable); }
独自定義のメソッドで検索結果のソートを行いたい場合は、メソッドの引数にorg.springframework.data.domain.Sort
を追加する
@Repository public interface CustomerRepository extends MongoRepository<Customer, String> { public List<Customer> findByCustomerSearchParam(CustomerSearchParam searchParam, Sort sort); }
キーワード | メソッド名サンプル | 条件 | 備考 |
---|---|---|---|
After | findByBirthdateAfter(Date date) | (日時が)引数の値より後 | |
Before | findByBirthdateBefore(Date date) | (日時が)引数の値より前 | |
GreaterThan | findByAgeGreaterThan(int age) | (数値が)引数の値より大きい | |
GreaterThanEqual | findByAgeGreaterThanEqual(int age) | (数値が)引数の値以上 | |
LessThan | findByAgeLessThan(int age) | (数値が)引数の値より小さい | |
LessThanEqual | findByAgeLessThanEqual(int age) | (数値が)引数の値以下 | |
Between | findByAgeBetween(int from, int to) findByAgeBetween(Range |
範囲指定 | 引数をintで指定した場合は境界値を含まない範囲指定となる。境界値を含む範囲指定で検索を行いたい場合はRangeで指定する |
In | findByAgeIn(Collection ages) | カラムの値が指定した配列のいずれかの値と等しい | |
NotIn | findByAgeNotIn(Collection ages) | カラムの値が指定した配列に存在しないか、カラムが存在しない | |
IsNotNull NotNull |
findByFirstnameNotNull() | カラムの値がnullでない | |
IsNull Null |
findByFirstnameNull() | カラムの値がnull | |
IsTrue True |
findByActiveIsTrue() | カラムの値がtrue | |
IsFalse False |
findByActiveIsFalse() | カラムの値はfalse | |
Exists | findByLocationExists(boolean exists) | true:カラムの値が存在するデータの検索 false:カラムの値が存在しないデータの検索 |
trueで検索されるデータには、カラムの値がnullのものも含まれる |
IgnoreCase | findByUsernameIgnoreCase(String username) | 正規表現での検索で大文字小文字を無視して検索 | |
キーワードなし | findByFirstname(String name) | 完全一致検索 | |
Not | findByFirstnameNot(String name) | not equal検索 | |
Regex | findByFirstnameRegex(String firstname) | 正規表現を使用して検索 | |
Like StartingWith EndingWith |
findByFirstnameLike(String name) | LIKE検索 | 引数には正規表現を指定 |
NotLike IsNotLike |
findByFirstnameNotLike(String name) | NOT LIKE検索 | 引数には正規表現を指定 |
Containing | findByFirstnameContaining(String name) | カラムの値に引数の値が含まれる | 引数には正規表現を指定 |
NotContaining | findByFirstnameNotContaining(String name) | カラムの値に引数の値が含まれない | 引数には正規表現を指定 |
Near | findByLocationNear(Point point) findByLocationNear(Point point, Distance max) findByLocationNear(Point point, Distance min, Distance max) |
位置情報検索 | |
Within | findByLocationWithin(Circle circle) findByLocationWithin(Box box) |
位置情報検索 | 引数で指定された形状内に完全に存在する地理空間データの検索 |
○範囲指定で使用する Rangeクラス
org.springframework.data.domain.Range
// closedメソッドで定義した範囲では境界値(1と5)も範囲に含まれる Range<Integer> closed = Range.closed(1, 5); System.out.println(closed.contains(5)); // true // openメソッドで定義した範囲では境界値(1と5)は範囲に含まれない Range<Integer> open = Range.open(1, 5); System.out.println(open.contains(5)); // false // leftOpenメソッドで定義した範囲では境界値(1)は範囲に含まれないが境界値(5)は範囲に含まれる Range<Integer> leftOpen = Range.leftOpen(1, 5); // rightOpenメソッドで定義した範囲では境界値(1)は範囲に含まれるが境界値(5)は範囲に含まれない Range<Integer> rightOpen = Range.rightOpen(1, 5);
○位置情報検索で使用するクラス
org.springframework.data.geo.Point
// 第一引数に経度、第二引数に緯度を指定 Point point = new Point(double x, double y);
org.springframework.data.geo.Distance
// 中心点からの距離を指定 Distance distance = new Distance(double value);
org.springframework.data.geo.Circle
// 第一、第二引数で円の中心の座標、第三引数に円の半径を指定 new Circle(double centerX, double centerY, double radius);
Serviceの作成
作成したリポジトリを呼び出すServiceを作成する。
import org.springframework.stereotype.Service; import jp.co.cti.template.webapp.mongo.Customer; import jp.co.cti.template.webapp.mongo.CustomerRepository; import lombok.extern.slf4j.Slf4j; /** * {@link SampleService}実装クラス。<br> */ @Service @Slf4j public class SampleServiceImpl implements SampleService { /** */ private CustomerRepository repository; /** * @param repository */ public CalculationServiceImpl(CustomerRepository repository) { this.repository = repository; } @Override public void insertToMongoDB() { repository.save(new Customer("Alice", "Smith")); } }
以下にデフォルトで用意されているメソッドの使用サンプルを示す。
登録
データの登録には、insert
もしくはsave
メソッドを使用する。
saveメソッドは、引数に指定したエンティティのIDのデータが既に存在した場合にはupdateを行うメソッドである。
メソッドの戻り値:登録/更新されたエンティティ
public void insert() { // エンティティでIDに値を設定しなかった場合は、「_id」にObjectIdが自動でふられる repository.save(new Customer("Alice", "Smith")); repository.insert(new Customer("Alice", "Smith")); // エンティティでIDに値を設定した場合は、「_id」に指定したIDを登録できる repository.save(new Customer("001", "Alice", "Smith")); // 複数件の登録も可能 List<Customer> list = List.of(new Customer("005", "中電", "三郎"), new Customer("006", "中電", "四郎")); repository.saveAll(list); repository.insert(list); }
更新
データの更新には、save
メソッドを使用する。
メソッドの戻り値:登録/更新されたエンティティ
public void update() { // 引数に指定したエンティティのIDと合致するデータが存在する場合更新 // ID未設定もしくは合致するIDが存在しない場合は登録 repository.save(new Customer("001", "Alice", "Smith")); // 複数件の更新も可能 List<Customer> list = List.of(new Customer("005", "中電", "三郎"), new Customer("006", "中電", "四郎")); repository.saveAll(list); }
削除
データの削除にはdelete
メソッドを使用する。
メソッドの戻り値:なし
public void delete() { // エンティティを指定して1件削除 repository.delete(new Customer("003", "中電", "太郎")); // IDを指定して削除 repository.deleteById("001"); // 複数件の削除(エンティティの指定) repository.deleteAll(List.of(new Customer("005", "中電", "三郎"), new Customer("006", "中電", "四郎"))); // 複数件の削除(IDの指定) repository.deleteAllById(List.of("003", "004")); // 全件削除 repository.deleteAll(); }
検索
データの検索にはfind
メソッドを使用する。
public void select() { // 全件検索 List<Customer> result = repository.findAll(); // ID検索 Optional<Customer> result = repository.findById("003"); // 複数ID検索 Iterable<Customer> result = repository.findAllById(List.of("003", "004")); // 検索結果のソート順を指定 // Sort#byメソッドの第1引数にソート順、第2引数にソートの基準となるカラムを指定する List<Customer> list = repository.findAll(Sort.by(Sort.Direction.ASC, "id")); // ページャー指定 // PageRequest#ofメソッドの第1引数に取得したいページ番号(0始まり)、 // 第2引数に1ページ当たりのデータ数、第3引数にSortのインスタンスを指定する PageRequest pageRequest = PageRequest.of(3, 3, Sort.by(Sort.Direction.ASC, "id")); Page<Customer> findAll2 = repository.findAll(pageRequest); Customer customer = new Customer(); customer.setFirstName("中電"); ExampleMatcher matcher = ExampleMatcher.matching(); Example<Customer> example = Example.of(customer, matcher); // Exampleで指定した条件に合うデータの検索 // 上記のExampleの場合「firstName=中電」のデータが検索される List<Customer> findAll = repository.findAll(example); // Exampleで指定した条件に合うデータのうち1件を取得 Optional<Customer> findOne = repository.findOne(example); }
データ存在確認
データの存在確認はexists
メソッドを使用する。
public void exists() { // IDに合致するデータが存在する場合true, 存在しない場合false boolean existsById = repository.existsById("001"); // Exampleで指定した条件に合うデータが存在する場合true, 存在しない場合false boolean exists = repository.exists(example); }
データ数カウント
データ数カウントはcount
メソッドを使用する。
public void count() { // コレクションに存在するデータ数を返す long count = repository.count(); // Exampleで指定した条件に合うデータ数を返す long count2 = repository.count(example); }