#Indexed annotation on nested class field not working - java

I have the following object structure:
#Document
public class User {
#Id
private ObjectId id;
private Contact info;
}
and here is the Contact pojo:
public class Contact {
private String mail;
}
I want to index on mail field inside Contact. I know I can define Compound Index on User class
#CompoundIndex(name = "mail", def = "{'info.mail': 1}")
But can I define this index in Contact class somehow using #Indexed annotation or some other way.
If I add #Document to Contact class, it creates a separate collection of Contact which I don't want. I want to store all information inside User collection only and define mail index in Contact class.

Related

How can I create a one-to-many relationship with Spring and thymeleaf?

I would like to create a "Product" class which has multiple "Tags" as a collection. So a one-to-many database whereas Product is "one" and Tags is "many".
The Tags will be defined in the HTML as an Input field and divided by spaces. For example "tag1 tag2 tag3".
My question now is: How can I retrieve the string from the input field and append them as a Collection to my product object?
What I have so far:
Product
#Entity
public class Product {
#Id
#GeneratedValue
private int barcode;
public String name;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
private Collection<Tag> tags;
...Getter & Setter
Tag
#Entity
public class Tag {
#Id
private String tagname;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "barcode", nullable = false)
private Product product;
...Getter & Setter
ProductsController: I tried to add Tag objects as a test but that throws errors that the Tag table does not exist
#PostMapping("/add")
public String add(#Valid Product product, BindingResult result, Model model) {
model.addAttribute("responseMessage", result);
if(!result.hasErrors()) {
//I tried to add a static collection to the product object, but it throws errors
Collection<Tag> col = new ArrayList<>();
col.add(new Tag("test"));
col.add(new Tag("test2"));
product.setTags(col);
productRepository.save(product);
}
model.addAttribute("products",productRepository.findAll());
return "products-add";
}
As you have the tags separated by space. First of all you need to make a String Array of tags using regex as shown below.
String tags = "tag1 tag2 tag3";
String[] tagArr = tags.split("\\s+");
Now you need to create a repository as below.
#Repository
public interface TagRepository extends JpaRepository<Tag, Long> {
Tag findByTagname(String tagname);
}
Create an interface for TagService.
public interface TagService {
Tag findByTagname(String tagname);
}
Create an implementation of TagService class
#Service
public class TagServiceImpl implements TagService{
#Autowired
private TagRepository tagRepository;
#Override
public Tag findByTagname(String tagname) {
return tagRepository.findByTagname(tagname);
}
}
Now fetching Tag by name is completed. Autowire your TagService into your controller class
#Autowire
private TagService tagService;
Add the below code to your controller.
String tags = "tag1 tag2 tag3";
String[] tagArr = tags.split("\\s+");
List<Tag> tagList = new ArrayList<Tag>();
for (String tagname : tagArr) {
Tag tag = tagService.findbyTagname(tagname);
tagList.add(tag);
}
Now when you save your product class. Set this list of tag into your it.
You must have a ProductService class in your service layer annotated with #Service.
You must create a method annotated with #Transactional in ProductService class
Your method must read all tags of a product and transform it to any collection you want.
Don't do it inside Controller. It is actually bad place to do same things.
Probably you are running this for first time and your database does not have table named Tag. Please make sure hibernate property hibernate.hbm2ddl.auto is set to 'update' which will automatically create required tables first before doing any insert of data.
And for converting string value tags separated by space, just use string.split() method which gives you array and then convert it to List to be set in Product object.

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 display the error message obtained from #Column (unique = true)?

I use JPA technology in my project.
Here is the entity:
#Entity
public class Cars implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="idCars")
private long idCars;
#Column(name="nomCars",unique=true)
private String nomCars;
}
Here is the controller:
#RestController
#RequestMapping(value="/Cars")
public class CarsRestController {
#RequestMapping(value="/AddCars")
public Cars AddCars(Cars cr){
return repository.save(cr);
}
}
I used the unique = true attribute to check if the new Cars object exists or does not exist in the DB. In case the object exists I want to retrieve this error message to display it after the web user.
Thanks,

NucleusUserException: Cannot access field on entity extending mapped superclass

I am running into a NucleusUserException while querying my google datastore instance. I am querying for a field that exists on a MappedSuperclass on the class that extends it. Here is my abstract class that contains the field I am interested in:
#Entity
#MappedSuperclass
#JsonIgnoreProperties({ "password" })
public abstract class AbstractUser implements User {
#Persistent
protected String emailAddress;
public void setEmailAddress(String email) {
this.emailAddress = email;
}
public String getEmailAddress() {
return this.emailAddress;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long key;
//Other stuff.
}
The concrete instance looks like this:
#Entity
public class Client extends AbstractUser {
//Things that only clients have.
}
My query that is failing looks like this:
List existingUsersWithEmail = manager
.createQuery(
"SELECT c from Client AS c WHERE c.emailaddress = :mail")
.setParameter("mail", request.getEmailAddress())
.getResultList();
The exception is this:
Cannot access field emailaddress on type org.workouthound.user.Client
org.datanucleus.exceptions.NucleusUserException: Cannot access field emailaddress on type org.workouthound.user.Client
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:552)
at org.datanucleus.query.compiler.JavaQueryCompiler.getType(JavaQueryCompiler.java:529)
at org.datanucleus.query.symbol.SymbolTable.getType(SymbolTable.java:118)
at org.datanucleus.query.expression.PrimaryExpression.bind(PrimaryExpression.java:118)
at org.datanucleus.query.expression.DyadicExpression.bind(DyadicExpression.java:85)
at org.datanucleus.query.compiler.JavaQueryCompiler.compileFilter(JavaQueryCompiler.java:299)
at org.datanucleus.query.compiler.JPQLCompiler.compile(JPQLCompiler.java:75)
at org.datanucleus.store.query.AbstractJPQLQuery.compileInternal(AbstractJPQLQuery.java:246)
at org.datanucleus.store.query.Query.setImplicitParameter(Query.java:690)
at org.datanucleus.jpa.JPAQuery.setParameter(JPAQuery.java:428)
at org.workouthound.rest.client.UserResources.emailIsRegistered(UserResources.java:55)
at org.workouthound.rest.client.UserResources.createClient(UserResources.java:33)
I am new to DataNucleus and Google Data Store. I attempted to follow the tutorial as outlined here however I very well could have missed something. Please let me know as additional information is necessary.
UPDATE:
If I change the field name to email as well as the getters, setters and query, it works...why?

Indexing composite object in spring mongodb

I have a composite object that I wish to store in mongodb (using spring annotations). The object is as follows:
#Document(collection="person")
class Person {
#Id
private String id;
private Address address;
private String name;
}
and the composite class Address:
#Document
class Address {
#Indexed
private Long countryId;
private String street;
#Indexed
private String city
}
I need both country and city to be indexed as part of the person collection. Alas, no index is created for them. Any ideas how to create the index?
I have tried the following which works but is not elegant:
#Document(collection="person")
#CompoundIndexes({
#CompoundIndex(name = "countryId", def = "{'address.countryId': 1}")
})
class Person {
You can set up multiple secondary indexes, if you wish. This would be a good place to start.

Categories