N1QL based query in couchbase of nested nested objects - java

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.

Related

How can I write SQL query in JPA repository with Spring Boot?

I'm doing a spring boot experiment and using MySQL.
For example, if I have a list of users, but I want to get the specified names, how can I write the SQL query that only indicates this situation?
This is my model class :
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
#Column(name="first_name")
public String name;
#Column (name="last_name")
public String last_name;
}
This is my JPA interface :
public interface CommentRepository extends JpaRepository<User , Long >{
// All C.R.U.D database methods
}
Finally, my controller area is as below :
#RestController
#RequestMapping(path="/api/v1/users")
public class CommentController {
#Autowired
CommentRepository repository ;
#GetMapping(path="/list")
public List<User> users() {
return repository.findAll();
}
}
Maybe you didn't understand my problem, I just want to write a customizable query of my own.
For example, I want to pull the data with the method I designed, while I normally pull the data by numbers with the find by id method.
You can either use methods that will be translated into queries or write your queries in the #Query annotation.
Please read the docs: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories

Saving same entity in different tables(same schema) using Jpa

I've using spring data JPA repositories to save the data into my tables.
In one of the situation, I've to store data in two different tables. These two tables have the exact same schema. But I can only store in one table as JpaRepository maps to just one table.
Example:
#Entity
#Table(name="users")
class User {
private Long userId;
private String firstName;
private String lastName;
}
interface MyRepo1 extends JpaRepositories<User,Long> {
}
interface MyRepo2 extends JpaRepositories<User,Long> {
}
Is there a way to map a single entity into multiple JpaRepositories? So, when I call MyRepo1.save(user) it saves in Users table and when I call MyRepo2.save(user), it saves in BackupUsers(exact same schema as Users) table.
Thanks
You should have two different entities, for instance, User entity AppUser entity, each one of them pointing to the different tables like this, assuming that the two table names are users and app_users:
#Entity
#Table(name="users")
public class User extends SuperUser {...}
and
#Entity
#Table(name="app_users")
public class AppUser extends SuperClass {...}
Of course, to avoid code duplication you can put your table fields in a superclass named SuperClass, for example:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class SuperUser {
#Id
private Long userId;
private String firstName;
private String lastName;
// getters and setters, constructors
}
After, you need to create two repositories for each entity class:
public interface UserRepository extends JpaRepositories<User, Long> {
}
public interface AppUserRepository extends JpaRepositories<AppUser,Long> {
}
NOTE: To finish, it's not recommended at all to have two tables that hold the same fields.
I don't think you can save in different tables with two different repositories, because you can't specify the table name in repository, but in the entity, I would suggest to use :
// class which hold common fields
class User {
private Long userId;
private String firstName;
private String lastName;
}
// entity for table 1
#Entity
#Table(name="table1")
class User1 extends User {}
// entity for table 1
#Entity
#Table(name="table2")
class User2 extends User {}
// repo for entity 1
interface MyRepo1 extends JpaRepositories<User1,Long> {}
// repo for entity 2
interface MyRepo2 extends JpaRepositories<User2 ,Long> {}

Associating Nested Object IDs in Spring JPA

In my Spring MVC/JPA application I have User and Department entities defined in respect to their database tables. As a rule many Users can belong to one Department, so I have the following in my User Class
#Entity(name = "USER")
public class User {
#Id
#Column(name = "Username")
private String username;
#ManyToOne
#JoinColumn(name = "Department")
private Department department;
}
When it comes time to save a new user I must associate the User with a Department's ID
User
username | BobbySurfs2020
departmentId | 43
Do I need to have an additional departmentId field defined on my User object just to make this association, or can I somehow use the embedded Department object to set this ID via my setter setDepartment()?
Update/Additional thought:
Is it even necessary to have Department nested in the User object like I have here? I'm thinking it would take up more memory to store a Department for every user I fetch than it would to associate only the Department ID's. That way if I needed a departments info at any time I could just simply look them up by the ID associated to the user. Thoughts?
Thanks much!
Do I need to have an additional departmentId field defined on my User object just to make this association.
No
Is it even necessary to have Department nested in the User object like I have here?
Yes. You are using an Object Relational Mapper so map objects.
In the MVC world you can easily handle this by means of a converter which will take the ID passed from the UI, look up the relevant entity and set this on the Entity being edited.
#Component
public class StringToDepartmentConverter implements Converter<String, Department> {
#Autowired
private DepartmentService service;
/**
*departmentId is the HTTP post param passed in by the framework
*/
public Department convert(String departmentId ) {
return service.findDepartment(Integer.parseInt(departmentId ));
}
}
Register this with the framework:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "..." })
public class MvcConfiguration extends WebMvcConfigurerAdapter{
//other configuration
#Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(departmentConverter());
}
#Bean
public StringToDepartmentConverter departmentConverter(){
return new StringToDepartmentConverter ();
}
}

SpringData MongoDB findBy Nested Property (non ID) Using DBRef

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.

Why does STS warn me about non matching parameters?

I am using Spring Data Jpa and created a JpaRepository for my User class.
The repository works but Spring Tool Suite gives me a warning for one method.
Following are examples of my domain model classes and the repository:
User:
#Entity
public class User {
#Id
#GeneratedValue
private long id;
private String username;
#ManyToMany
#JoinTable( ... )
private Set<Role> roles = new HashSet<>();
// Getters & setters
}
Role:
#Entity
public class Role {
#Id
#GeneratedValue
private Long id;
private String name;
// Getters & setters
}
UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByRoles(Set<Role> roles);
}
STS marks the method findByRoles() and gives the following message: Parameter type (Set<Role>) does not match domain class property definition (Set).
Why do I get this warning?
change your method name like this
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findBy_Roles(Set<Role> roles);
}
for more details why its complaining see this page heading "2.4.3. Property expressions".
The signature of the method is wrong. It should be List<User> findByRolesIn(Set<Role> roles), because the argument is a collection.

Categories