Issue
GoodEvening i'm new about mongo, and i choose to use a mix & match of RepositoryPattern and Mongotemplate
Now i find a very strange error when i want to use MongoTemplate to retrive a specific value of an inner object in order to calculate a progressive ID It seems my code work for 0 or 1 document inside a collection, but when i have equal or more than 2 documents, the method will throw a
org.springframework.dao.IncorrectResultSizeDataAccessException: Query { "$java" : Query: {}, Fields: {}, Sort: {} } returned non unique result.
as if limit dosen't work. I have just, for now, a rest and a repository pattern, but in the service layer i have another autowire whit mongotemplate class, this template is used by just 1 method.
public DetailedOrder findTheBiggestBy(String byWhat){
Query query = new Query();
query.with(Sort.by(Sort.Direction.DESC,byWhat)).limit(1);
return mongoDb.findOne(query,DetailedOrder.class);
}
As you can see is pretty simple and it actually work, becouse before moving the Template inside Service it actually work whit various documents inside collection, when i autowired it over the rest layer.
There is something i miss and is not rly related to mongo but related to spring autowire?
My detailorderClass is
package com.service.backend.BK.Pojo;
import com.service.backend.BK.Constants.Constant;
import org.bson.codecs.pojo.annotations.BsonId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.FieldType;
import org.springframework.data.mongodb.core.mapping.MongoId;
import java.util.List;
@Document("Orders")
public class DetailedOrder {
@MongoId(FieldType.OBJECT_ID)
private String id;
@Field
private List<Integer> category;
// 1 junk to 10 Pristine
@Field
private Integer quality;
@Field
private BaseOrder baseOrder;
@Field
private String qualityDescription;
public DetailedOrder(){}
public DetailedOrder(String Description,Double price, List<Integer> category, Integer quality) {
this.category = category;
this.quality = quality;
this.qualityDescription = qualityDescriptionPairFactory(quality);
this.baseOrder=new BaseOrder(Description,price);
}
public List<Integer> getCategory() {
return category;
}
public void setCategory(List<Integer> category) {
this.category = category;
}
public Integer getQuality() {
return quality;
}
public void setQuality(Integer quality) {
this.quality = quality;
}
public String getQualityDescription() {
return qualityDescription;
}
public void setQualityDescription(String qualityDescription) {
this.qualityDescription = qualityDescription;}
private String qualityDescriptionPairFactory(int quality){
switch (quality){
case 1:return Constant.Quality.NOGRAD.label;
case 2:return Constant.Quality.HEAVYDMN.label;
case 3:return Constant.Quality.LOOSE.label;
case 4:return Constant.Quality.POOR.label;
case 5:return Constant.Quality.LIGHTDMN.label;
case 6:return Constant.Quality.GOOD.label;
case 7:return Constant.Quality.EXCELENT.label;
case 8:return Constant.Quality.NEARMINT.label;
case 9:return Constant.Quality.MINT.label;
case 10:return Constant.Quality.NEWUNRL.label;
default:return Constant.Quality.NOGRAD.label; }
}
@Override
public String toString() {
return "DetailedOrder{" +
"id='" + id + '\'' +
", baseOrder='" + getBaseOrder().returnBaseOrder() + '\'' +
", category=" + category +
", quality=" + quality +
", qualityDescription='" + qualityDescription + '\'' +
'}';
}
public BaseOrder getBaseOrder() {
return baseOrder;
}
public void setBaseOrder(BaseOrder baseOrder) {
this.baseOrder = baseOrder;
}
public void setId(String id) {
this.id = id;
}
}
and that lead to baseOrderClass
package com.service.backend.BK.Pojo;
import org.joda.time.DateTime;
import org.springframework.data.mongodb.core.mapping.Document;
public class BaseOrder {
private String id;
private String description;
private Double desideredPrice;
//Pending,active,Rejected,Hault,etc etc
private int status;
protected BaseOrder(){}
protected BaseOrder(String description, Double desideredPrice) {
this.description = description;
this.desideredPrice = desideredPrice;
}
public String returnBaseOrder(){
return "BaseOrder{" +
"id='" + id + '\'' +
", description='" + description + '\'' +
", desideredPrice=" + desideredPrice +
", status=" + status +
'}';
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getDesideredPrice() {
return desideredPrice;
}
public void setDesideredPrice(Double desideredPrice) {
this.desideredPrice = desideredPrice;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
//###############################################################################################################//
}
Solution
The OPs question related to a spring context issue. By just accessing the repository directly the problem could be resolved.
Within the comments an additional question/target has been found, i would like to provide an answer for that.
How to have persistence access within the domain layer?
I have created a repository at GitHub where you can find a working solution. This code is not best practice but will provide a solution that works.
Every constructed domain object needs access to the declared repositories. That can be a problem when using dependency injection. In order to keep entity construction pristine an abstract class has been introduces that takes the task to get the concrete repositories.
The core idea is to make the Spring ApplicationContext
accessable statically. Having this context an access to the repositories is just one call away.
Beans having the ApplicationContextAware
interface will be called in a very early stage of Spring Boots startup. When using this class to access the context every consumer has to call it after Spring has been loaded. This can be achieved by using @Component
, @Configuration
, @Bean
to run code and there will be no race condition.
Further details are within the repositories readme file.
I hope that this helps you :)
Answered By - wartoshika
Answer Checked By - Willingham (JavaFixing Volunteer)