I need to get the average duration of all the iterations made. I have the entity entity that I explain below:
#Document(collection = IterationEntity.COLLECTION_NAME)
public class IterationEntity {
public final static String COLLECTION_NAME = "iterations";
#Id
private ObjectId id;
#Field("start_date")
private Date startDate;
#Field("finish_date")
private Date finishDate;
#Field("duration")
private Long duration;
#Field("total_tasks")
private Integer totalTasks = 0;
#Field("total_failed_tasks")
private Integer totalFailedTasks = 0;
#Field("total_comments")
private Integer totalComments = 0;
#Field("tasks")
#DBRef
#CascadeSave
private Set<TaskEntity> tasks = new HashSet<>();
}
I have implemented a custom repository method to perform this operation but I get an error when I get the result.
#Override
public Long getAvgDuration() {
GroupOperation avgOperation = Aggregation.group()
.sum("duration")
.as("total_duration")
.avg("total_duration")
.as("avg_duration");
Aggregation aggregation = newAggregation(IterationEntity.class, avgOperation);
return mongoTemplate.aggregate(aggregation, IterationEntity.COLLECTION_NAME, Long.class).getUniqueMappedResult();
}
When the method is executed I get this exception:
org.springframework.data.mapping.model.MappingException: No mapping metadata found for java.lang.Long
Thanks in advance.
In order to map the aggregation result correctly it needs to be mapped to a domain type or simply the Document returned.
Something like below should do what you're looking for.
class AggResult {
#Field("total_duration") Long duration;
#Field("avg_duration") Double avgDuration;
}
return template
.aggregate(aggregation, COLLECTION_NAME, AggResult.class)
.getUniqueMappedResult()
.getAvgDuration();
Related
I have the below object
#Document(collection = "qr_code")
public class QrCode implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String qrCodeId;
#Field
private String codePay;
private LocalDateTime expiredIn;
}
I have this query to check if a codePay exists or not
boolean existsByCodePay(String codePay);
I want another query to check if a QrCode is expired or not, based on attribute expiredIn, that's to say the QrCode expired when expiredIn < LocalDateTime.now()
#Query(???)
boolean isQrCodeExpired(String codePay);
The raw mongodb query can be something like this :
{
"expiredIn":{
$gt : new Date()
}
}
I have below two Document structures. In the structure CRMContact.orgGroupId == OrganizationGroup.id. I would like to fetch all the CRMContact document that matches with sharedGroupIds and also select only a few fields from CRMContact and only OrganizationGroup.groupownername from OrganizationGroup and match/populate groupId (with only one field [groupownername] populated). I have used below custom implementation but didn't work.
I have included aggregarionsNotWorking which is not working and aggregarions returning entire OrganizationGroup populated. How to achieve this i.e. just to populate groupownername field, using spring data mongodb?
#Document(collection = "ww_crm_contact")
public class CRMContact{
#Id
protected String id;
private String displayName;
private String firstName;
private String middleName;
private String lastName;
private OrganizationGroup groupId; //Ignore //Modified field name orgGroupId
#Indexed(name = "CRMCONTACT_SHAREDGROUPID_IDX",background = true)
private List<String> sharedGroupIds = new LinkedList<>();
#Indexed(name = "CRMCONTACT_ORGGROUPID_IDX",background = true)
private String orgGroupId;
}
#Document(collection = "ww_organization_groups")
public class OrganizationGroup {
private static final long serialVersionUID = 600049975643062552L;
#Id
protected String id;
private String groupName;
private int riaId;
private Boolean isPrivate;
private String description;
private Boolean deleted;
#Transient
private int count;
private String groupownerid;
private String groupownername;
}
#Repository
public class CustomCRMContactDAO {
#Autowired
MongoTemplate mongoTemplate;
public List<CRMContact> getContactsPresentInGroup(List<ObjectId> objectIds){
LookupOperation lookupOperation = LookupOperation.newLookup().from("ww_organization_groups").localField("orgGroupId").foreignField("_id").as("groupId");
ProjectionOperation fields = project("firstName","lastName", "primaryId","displayName","groupId.groupownername");
Aggregation aggregarionsNotWorking = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,unwind("groupId"),fields); //Not Working even if I change the field only to groupownername
Aggregation aggregarions = Aggregation.newAggregation(Aggregation.match(Criteria.where("sharedGroupIds").in(objectIds)),lookupOperation,fields); //
List<CRMContact> crmContacts = mongoTemplate.aggregate(aggregarions, "ww_crm_contact",CRMContact.class).getMappedResults();
return crmContacts;
}
}
I have the following Spring Data MongoDB document:
#Document(collection = "messages")
#CompoundIndexes({ #CompoundIndex(name = "chatId_messageId", def = "{'chatId': 1, 'messageId': 1}") })
public class Message implements Serializable {
private static final long serialVersionUID = -1590112217771926691L;
#Id
private String id;
private Long chatId;
private Integer messageId;
private Post post;
}
the Post model(which is not Spring Data MongoDB document) looks like:
public class Post implements Serializable {
private static final long serialVersionUID = -886664249197573502L;
private String id;
}
I'd like to add index to the Message.post.id field.
How it can be done with Spring Data MongoDB and Message.post field declaration in Message document ?
If you want to add Message.post.id to an already compound index, then do it like
#Document(collection = "messages")
#CompoundIndexes({ #CompoundIndex(name = "chatId_messageId", def = "{'chatId': 1, 'messageId': 1, 'Message.post.id' : 1}") })
public class Message implements Serializable {
private static final long serialVersionUID = -1590112217771926691L;
#Id
private String id;
private Long chatId;
private Integer messageId;
private Post post;
}
Compound indexes are indexes that have more than one indexed field, so ideally, the most restrictive field should be to the left of the B-tree. If you want to index by sex and birth, for instance, the index should begin by birth, as it is much more restrictive than sex.
Or if you want to treat it as a saperate index, then create index using #Indexed like
public class Post implements Serializable {
private static final long serialVersionUID = -886664249197573502L;
#Indexed
private String id;
}
Updated
For more info regarding how queries with sub fields of compound index works, check Documentation
I have the above domain structure where I have list of Companies in the product and the aim is not make entry in mongoDB when I have exact match for companies & productId already present in the DB.
#Entity
public class Mobile {
#Id
private Integer id;
private String imei;
private Product productInfo;
// ...
}
#Entity
public class Product {
#Id
private Integer id;
private String productId;
private List<Company<?>> companies;
// ...
}
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(name= "samsung", value = Samsung.class),
#JsonSubTypes.Type(name= "htc",value = Htc.class)})
public class Company<T> implements Serializable {
private static final long serialVersionUID = -8869676577723436716L;
private T companyInfo;
private String type;
// ...
}
I am using mongo template and I have tried to use find as shown below but id didn't work
template.find(Query.query(Criteria.where("product.companies").is(companList),Mobile.class);
Say I have a Collection defined like bellow:
#Document(collection = "Item")
public class Item {
#Id
private String id;
private String title;
private String mrp;
private String discount;
//getters and setters goes here
}
I need to find all items which are sorted on [mrp - discount] value.
How to express this using MongoOperations
That's what the Aggregation Framework is for. Spring Data MongoDB offers aggregate via MongoOperations.
TypedAggregation<Item> agg = newAggregation(Item.class,
project()
.andExpression("mrp - discount").as("total")
.andInclude("mrp", "discount", "id"),
sort(new Sort(ASC, "total")));