J'ai besoin d'écrire une application avec laquelle je peux faire des requêtes complexes en utilisant spring-data et mongodb. J'ai commencé par utiliser MongoRepository, mais je me suis débattu avec des requêtes complexes pour trouver des exemples ou pour comprendre la syntaxe.
Je parle de requêtes comme celle-ci:
@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
List<User> findByEmailOrLastName(String email, String lastName);
}
ou l'utilisation de requêtes basées sur JSON que j'ai essayées par essais et erreurs car je ne comprends pas bien la syntaxe. Même après avoir lu la documentation de mongodb (exemple non fonctionnel en raison d’une syntaxe incorrecte).
@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);
}
Après avoir lu toute la documentation, il semble que mongoTemplate
soit beaucoup mieux documenté que MongoRepository
. Je fais référence à la documentation suivante:
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
Pouvez-vous me dire ce qui est plus pratique et puissant à utiliser? mongoTemplate
ou MongoRepository
? Est-ce que les deux ont la même maturité ou est-ce que l'un d'eux manque de plus de fonctionnalités que l'autre?
"Pratique" et "puissant à utiliser" sont en quelque sorte des objectifs contradictoires. Les référentiels sont de loin plus pratiques que les modèles, mais ces derniers vous donnent bien sûr un contrôle plus fin sur ce qu’il faut exécuter.
Le modèle de programmation du référentiel étant disponible pour plusieurs modules Spring Data, vous en trouverez une documentation plus détaillée dans la section générale de Spring Data MongoDB documentation de référence .
TL; DR
Nous recommandons généralement l'approche suivante:
MongoTemplate
.Détails
Pour votre exemple, cela ressemblerait à quelque chose comme ceci:
Définissez une interface pour votre code personnalisé:
interface CustomUserRepository {
List<User> yourCustomMethod();
}
Ajoutez une implémentation pour cette classe et suivez la convention de dénomination pour vous assurer que nous pouvons trouver la classe.
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
}
}
Laissez maintenant votre interface de référentiel de base étendre celle personnalisée et l'infrastructure utilisera automatiquement votre implémentation personnalisée:
interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {
}
Ainsi, vous aurez essentiellement le choix: tout ce qui est facile à déclarer va dans UserRepository
, tout ce qui est mieux implémenté manuellement va dans CustomUserRepository
. Les options de personnalisation sont documentées ici .
Cette réponse est peut-être un peu retardée, mais je recommanderais d'éviter toute la route du référentiel. Vous obtenez très peu de méthodes implémentées de grande valeur pratique. Pour que cela fonctionne, vous rencontrez le non-sens de la configuration de Java) sur lequel vous pouvez passer des jours et des semaines sans beaucoup d'aide dans la documentation.
Au lieu de cela, utilisez la route MongoTemplate
et créez votre propre couche d'accès aux données, ce qui vous libère des cauchemars de la configuration rencontrés par les programmeurs Spring. MongoTemplate
est vraiment le sauveur des ingénieurs qui sont à l'aise pour concevoir leurs propres classes et interactions, car ils disposent de beaucoup de flexibilité. La structure peut être quelque chose comme ceci:
MongoClientFactory
à exécuter au niveau de l'application et créez un objet MongoClient
. Vous pouvez l'implémenter en tant que Singleton ou en utilisant un Enum Singleton (c'est thread-safe)FWIW, concernant les mises à jour dans un environnement multithread:
MongoTemplate
fournit updateFirst
, updateMulti
, findAndModify
, upsert
.. méthodes permettant de modifier un document en une seule opération. L'objet Update
utilisé par ces méthodes vous permet également de ne cibler que les champs pertinents.MongoRepository
ne vous donne que les opérations de base find
, insert
, save
, delete
, qui fonctionnent avec POJO contenant tous les champs. Cela vous oblige à mettre à jour les documents en plusieurs étapes (find
le document à mettre à jour, à modifier les champs pertinents à partir du POJO renvoyé, puis à save
it), ou à définir vos propres requêtes de mise à jour par main en utilisant @Query
.Dans un environnement multi-thread, comme par exemple a Java back-end avec plusieurs REST points de terminaison, les mises à jour à une seule méthode sont la solution à privilégier, afin de réduire les risques que deux mises à jour simultanées en écrasent une les changements d'un autre.
Exemple: donné un document comme celui-ci: { _id: "ID1", field1: "a string", field2: 10.0 }
et deux threads différents le mettant simultanément à jour ...
Avec MongoTemplate
, cela ressemblerait un peu à ceci:
THREAD_001 THREAD_002
| |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
| |
| |
et l'état final du document est toujours { _id: "ID1", field1: "another string", field2: 15.0 }
puisque chaque thread accède au DB une seule fois et seul le champ spécifié est modifié.
Alors que le même scénario avec MongoRepository
ressemblerait à ceci:
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)
| |
| |
et le document final étant soit { _id: "ID1", field1: "another string", field2: 10.0 }
ou { _id: "ID1", field1: "a string", field2: 15.0 }
selon l'opération save
qui frappe le DB en premier.
Donc, je dirais que MongoTemplate
est une meilleure option , sauf si vous avez un modèle POJO très élaboré ou avez besoin des capacités de requête personnalisées de MongoRepository
pour une raison quelconque.