Spring-dataとmongodbを使用して複雑なクエリを実行できるアプリケーションを作成する必要があります。私はMongoRepositoryを使用することから始めましたが、例を見つけるため、または実際に構文を理解するために複雑なクエリに苦労しました。
私はこのようなクエリについて話している:
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);
}
または、構文が正しくないため試行錯誤して試したJSONベースのクエリの使用。 mongodbのドキュメントを読んだ後でも(間違った構文による動作しない例)。
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
@Query("'$or':[{'firstName':{'$regex':?0,'$options':'i'}},{'lastName':{'$regex':?0,'$options':'i'}}]")
List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);
}
すべてのドキュメントを読んだ後、mongoTemplate
はMongoRepository
よりもはるかに優れたドキュメントになっているようです。私は次のドキュメントを参照しています:
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
より便利で強力なものを教えてください。 mongoTemplate
またはMongoRepository
?両方とも成熟しているか、または一方が他方より多くの機能を欠いていますか?
「便利」と「強力な」は、ある程度矛盾する目標です。リポジトリはテンプレートよりもはるかに便利ですが、後者はもちろん実行するものをよりきめ細かく制御できます。
リポジトリプログラミングモデルは複数のSpring Dataモジュールで利用できるため、Spring Data MongoDBの一般セクションで詳細なドキュメントを見つけることができます reference docs 。
TL; DR
通常、次のアプローチをお勧めします。
MongoTemplate
を使用します。詳細
あなたの例では、これは次のようになります。
カスタムコードのインターフェイスを定義します。
interface CustomUserRepository {
List<User> yourCustomMethod();
}
このクラスの実装を追加し、命名規則に従ってクラスを見つけられるようにします。
class UserRepositoryImpl implements CustomUserRepository {
private final MongoOperations operations;
@Autowired
public UserRepositoryImpl(MongoOperations operations) {
Assert.notNull(operations, "MongoOperations must not be null!");
this.operations = operations;
}
public List<User> yourCustomMethod() {
// custom implementation here
}
}
ベースリポジトリインターフェースでカスタムインターフェースを拡張し、インフラストラクチャがカスタム実装を自動的に使用するようにします。
interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {
}
このようにして、基本的に選択肢を得ることができます。宣言が簡単なものはすべてUserRepository
に、手動で実装する方がよいものはすべてCustomUserRepository
になります。カスタマイズオプションは here で文書化されています。
この答えは少し遅れることがありますが、リポジトリ全体のルートを避けることをお勧めします。実用的な価値のある実装されたメソッドはほとんどありません。それを機能させるために、Java構成のナンセンスにぶつかります。これは、ドキュメンテーションの助けがなくても何日も何週間も費やすことができます。
代わりに、MongoTemplate
ルートを使用して、独自のデータアクセスレイヤーを作成し、Springプログラマが直面する構成の悪夢から解放します。 MongoTemplate
は、柔軟性が非常に高いため、独自のクラスと相互作用を快適に設計できるエンジニアにとって本当に救い主です。構造は次のようになります。
MongoClientFactory
クラスを作成し、MongoClient
オブジェクトを提供します。これをシングルトンとして実装するか、Enumシングルトンを使用して実装できます(これはスレッドセーフです)FWIW、マルチスレッド環境での更新に関して:
MongoTemplate
は、すぐに使用できるupdateFirst
、updateMulti
、findAndModify
、upsert
...メソッドを提供し、1回の操作でドキュメントを変更できるようにします。これらのメソッドで使用されるUpdate
オブジェクトを使用すると、関連するフィールドのみをターゲットにすることもできます。MongoRepository
は、すべてのフィールドを含むPOJOで動作する基本的なfind
、insert
、save
、delete
操作のみを提供します。これにより、ドキュメントをいくつかの手順で更新する(find
更新するドキュメント、返されたPOJOから関連フィールドを変更し、save
it)、または@Query
を使用して手動で更新クエリを定義します。マルチスレッド環境では、例えば複数のJavaエンドポイントを持つRESTバックエンドでは、2つの同時更新が互いの変更を上書きする可能性を減らすために、単一メソッドの更新を行う方法です。
例:次のようなドキュメントを指定します:{ _id: "ID1", field1: "a string", field2: 10.0 }
と2つの異なるスレッドが同時にそれを更新しています...
MongoTemplate
を使用すると、次のようになります。
THREAD_001 THREAD_002
| |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
| |
| |
ドキュメントの最終状態は常に{ _id: "ID1", field1: "another string", field2: 15.0 }
です。これは、各スレッドがDBに一度だけアクセスするためですand指定されたフィールドのみが変更されます。
MongoRepository
を使用した同じケースシナリオは次のようになります。
THREAD_001 THREAD_002
| |
|pojo = findById("ID1") |pojo = findById("ID1")
|pojo.setField1("another string") /* field2 still 10.0 */ |pojo.setField2(pojo.getField2()+5) /* field1 still "a string" */
|save(pojo) |save(pojo)
| |
| |
最後のドキュメントは、どのsave
操作が最初にDBにヒットするかに応じて、{ _id: "ID1", field1: "another string", field2: 10.0 }
または{ _id: "ID1", field1: "a string", field2: 15.0 }
のいずれかになります。
非常に精巧なPOJOモデルを持っているか、何らかの理由でMongoTemplate
のカスタムクエリ機能が必要でない限り、MongoRepository
の方が優れたオプションです。