SpringData MongoDB findBy Nested Property (non ID) Using DBRef - java

Using SpringData MongoDB (spring-data-mongodb 1.9.1.RELEASE) I am needing to query a User based on a User's Role linked by #DBRef.
User
#Document(collection = "user")
public class User {
private String userName;
private boolean isActive;
#DBRef
private List<Role> roles;
}
Role
#Document(collection = "role")
public class Role {
private String roleName;
private String description;
private long roleNum;
}
User Repository
#Repository
public interface UserRepository extends MongoRepository<User, String> {
public User findByUserName(String username);
#Query(value = "{'roles.$roleName' : ?0}")
public List<User> findByRolesRoleName(String roleName);
}
A question similar has been asked, but not answered. Makes me think that maybe this type of findBy is not supported.
This seems fairly straight forward, however, the results of findByRolesRoleName is always an empty list (size = 0).
Has anyone gotten a findBy for this type of relationship working properly?

It is not possible to query on non id properties of DBRef in MongoDB itself. Thus it is not possible to do so using Spring Data MongoDB.

Related

Spring get all with a set of custom object with correct ID

I have a User object, and a Ticket object that have a ManyToMAny relationship
class User{
private Long id;
#ManyToMany
private Set<Ticket> tickets;
}
class Ticket{
#ManyToMany
private Set<User> users;
}
Obviously this is a very simplified pseudo-like version of the code, but what would i name the method in my JPA Repository, to get all of the tickets that have a user with the specified ID in it? Is this possible, or should I make a custom query?
You can write 2 different named queries:
public interface TicketRepository extends JpaRepository<Ticket, Long> {
List<Ticket> findAllByUsers(User user);
List<Ticket> findAllByUsersIdIn(List<Long> userIds);
}
Method findAllByUsers(..) takes User object to search and return results, method findAllByUsersIdIn(..) takes user ids to search and return results.

How to get object from nested entities in Spring/JPA/Hibernate?

I have this entities:
public class AnswerEntity {
#ManyToOne
private UserEntity user;
#ManyToOne
private AnswerDirectoryEntity answer;
#ManyToOne
private QuestionEntity question;
}
public class QuestionEntity {
#ManyToOne
private QuestionnaireEntity questionnaire;
}
public class QuestionnaireEntity {
private String code;
}
I need to take all user answers by user ID and corresponding code from QuestionnaireEntity.
I do it by create query like this:
List<AnswerEntity> answerList = answerRepository.findAllByUserId(userId);
and iterate over each object in my list and with using equals I compare each object to my questionnaire code:
for(AnswerEntity answerEntity : answerList){
if(answerEntity.getQuestion().getQuestionnaire().getCode().equals(questionnaireId)){
///
}
but this solution is very slow because it must iterate each object from my database,
can anybody tell my how to create an query in my repository which can help me?
You can use JPA method query this way in repository
List<AnswerEntity> findByUserIdAndQuestionQuestionnaireCode(Integer userId, String code);

Spring JPA - Implement unique constraints in code - Tx isolation level

I need to implement unique constrain validation using spring data jpa, and i know it can be done with jpa annotations but i need to do it manually.
I have a class (entity) User like this:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
private Date createdAt;
}
When i create a new User i have to validate that no other user with identical username or password exists.
I know i need to do something like this (more or less):
public interface UserRepository extends JpaRepository<User, Long> {
public List<User> findByUsernameOrEmail(String username, String email);
}
public class UserService {
#Autowired
private UserRepository userRepository;
#Transactional
public User create(User user) {
List<User> users = this.userRepository.findByUsernameOrEmail(user.getUsername(), user.getEmail());
if (users.size() > 0)
throw new RuntimeException("No repeated username or email allowed");
User newUser = this.userRepository.save(user);
return newUser;
}
}
My question is: what type of transaction isolation level should i use ?
Is it REPETEABLE_READ enough ? I need to avoid duplicated users

N1QL based query in couchbase of nested nested objects

I'm working on a professional social network application using couchbase server 4.1 with spring data couchbase 2.2.4 in a spring boot application using java 1.8.
I want to replace the next stream which searches a LikeEntity with specific company in the database by a N1QL based query which searches a user with the same previous likeEntity unnested:
Here is the service containing the stream to replace by the query:
#Service
class CompanyServiceImpl implements CompanyService{
#Override
public void addCompanyToLike(UserEntity user, Company company){
int incrementValue=1;
LikeEntity existingLike=user.getLikeEntities()
.stream()
.filter(le->le.getCompany().getName().equals(company.getName()))
.findFirst();
//rest of process
}
}
Here is the different java beans you will need to look at:
UserEntity class:
#Document
#ViewIndexed(designDoc = "user")
class UserEntity implements Serializable{
#Field private String id;
#Reference
private List<LikeEntity> likeEntities=new ArrayList<LikeEntity>();
//Other attributes plus getters and setters:
}
LikeEntity class:
#Document
class LikeEntity implements serializable{
#Reference
private Company company;
#Reference
private Job job;
// other attributes plus getters and setters
}
As you see above, the LikeEntity class may contain any object liked by the user, it can be a company, a job or another object. Also the LikeEntity is stored only inside a user document as element of user's list of likes and not independately in the database.It's my choice of modelization because the LikeEntity won't by used in other java beans of my application
Company:
#Document
#ViewIndexed(designDoc = "company")
class Company implements Serializable{
#Field private String id;
#Field private String name;
//Other attributes plus getters and setters
}
N.B: I've tried the next query inside UserRepository but it didn't work:
UserRepository:
#Repository
#N1qlPrimaryIndexed
#N1qlSecondaryIndexed(indexName = "user")
public interface UserRepository extends CouchbaseRepository<UserEntity, String> {
#Query("SELECT b.*, likeEntity FROM #{#n1ql.bucket} AS b UNNEST b.likeEntities AS likeEntity WHERE b.id=$1 AND likeEntity.company.name=$2")
UserEntity findByLikedCompanyName(String idUser
, String companyName);
}
I'm looking for your answers, and thank you so much in advance.

How to use projecting types in Spring Data MongoDB repository's query methods?

I have been playing around with Spring Data and MongoDB and have a question about limiting the amount of data for certain queries. I've seen adding custom queries within the MongoRepository, however I haven't seen any examples of limiting the amount of data and returning classes that are basically a subset of larger classes.
For instance I have a User class that has several fields, but I also want to create a UserShort class that has a subset of the fields in the User class. For instance UserShort would only contain the id and firstName / lastName / email fields, rather than everything.
I've seen I can specify/limit the fields that are returned, but can I have those returned into a different class? At the moment the UserShort will return null unless I specify the User class instead, but the fields will be limited to the ones I specify. Wasn't sure if this is possible at all? I realize the User class below isn't huge, but it's the concept I'm after.
A user interface:
public interface Users {}
Subset class:
public class UserShort implements Users {
#Id
private String id;
private String firstName;
private String lastName;
#Indexed(unique = true)
private String email;
//getters / setters
}
Full class:
#Document
public class User implements Users {
#Id
private String id;
private String firstName;
private String lastName;
private String username;
private String password;
private Date dob;
private Status status;
#Indexed(unique = true)
private String email;
private Gender gender;
private String locale;
private Date registerDate;
#DBRef
private List<UserAddress> addresses;
public User(){
addresses = new ArrayList<UserAddress>();
}
//getters / setters
}
And the repository interface:
public interface UserRepository extends MongoRepository<Users, String> {
public User findByEmail(String email);
#Query(value="{ 'email' : ?0 }", fields="{ 'firstName' : 1, 'lastName' : 1}")
public UserShort findUserShortByEmail(String email);
}
As long as the return type of the query method is assignable to the managed domain type (Users in your case) we will prefer the return type to determine the collection to run the query against. Thus, in your case we'd execute the query against userShort instead of users which is why you do not get any results. That behavior is in place to support storing inheritance hierarchies into different collections.
If you switched to User as the domain type for the repository, things should work exactly as expected. This would also have the benefit of preventing clients from handing UserShort instances to the save(…) method which will wipe out properties contained in User but not in UserShort. Here's the final repository interface declaration.
interface UserRepository extends MongoRepository<User, String> {
User findByEmail(String email);
#Query(value="{ 'email' : ?0 }", fields="{ 'firstName' : 1, 'lastName' : 1}")
UserShort findUserShortByEmail(String email);
}
P.S.: #byte-crunch outlined in the comments that this currently only works for collections of projections but not for returning single instances. This has been reported and fixed in DATAMONGO-1030 and will be available in 1.5.4 and 1.6.0 GA.

Categories