I have a JavaScript code.
db.xxx.aggregate([
{$project: {object:{$first:'$object.array'}, _id:0}}
])
I don't know how to overwrite it by java client.
import org.springframework.data.mongodb.core.MongoTemplate;
...
Aggregation.newAggregation(
Aggregation.project().andExclude("_id").???
)
And where to find the usage?
This is TestDocument
public class TestArrayDocument {
#Id
String id;
Integer[] x;
}
Inject MongoTemplate
#Autowired
MongoTemplate mongoTemplate;
This is aggregate method
TypedAggregation<TestArrayDocument> aggregation = Aggregation.newAggregation(TestArrayDocument.class,Aggregation
.project()
.andExclude("_id")
.andExpression("first(x)").as("object"));
List<Map> mapData= mongoTemplate
.aggregate(aggregation,Map.class)
.getMappedResults();
x is your $object.array.
return in LinkedHashMap "object"=>"firstElement".
Related
I have a DAOImpl with an override function. I'm trying to use an aggregation to first filter then match then to project.
public Map<Long, Integer> getUsersByAccount() {
MatchOperation filterByAccountId = match(new Criteria(ACCOUNT_ID).nin(Arrays.asList(null, "")));
GroupOperation groupByMasterAccount = group(DEFAULT_MASTER_ACCOUNT_ID).count().as("countOfFooUsers");
ProjectionOperation projectByIDandCount = project()
.and("_id")
.as("defaultMasterAccountId");
projectByIDandCount.and("countOfFooUsers");
Aggregation aggregation = newAggregation(
filterByAccountId,
groupByMasterAccount,
projectByIDandCount
);
AggregationResults<MAandUsers> maUsersResult = mongoTemplate
.aggregate(aggregation, USERS_COLLECTION, MAandUsers.class);
The inner class above MAandUsers within the IMPL:
#Data
public static class MAandUsers {
private Long defaultMasterAccountId;
private Integer countOfFooUsers;
}
However, my maUsersResultreturns a null value for countOfFooUsers when, in my test case, there should be 1. I'm assuming my projection operation is off ---> projectByIDandCount.and("countOfFooUsers");
Is there a way for me to use spring's mongotemplate to receive back multiple values on projection operations? I'm fairly new to this
Try using, andInclude
ProjectionOperation projectByIDandCount = project()
.and("_id").as("defaultMasterAccountId")
.andInclude("countOfFooUsers");
Working with a Spring Boot and Spring data, I have this Mongo Doc:
#Document(collection = "dogs")
public class Dog{
#Id
private long dogId;
private LocalDateTime creationDate;
...
}
I added this method to the Repository:
#Repository
public interface DogRepository extends CrudRepository<Dog, Long>, PagingAndSortingRepository<Dog, Long> {
Page<Dog> findAllByCreationDateAfterAndCreationDateBefore(LocalDateTime createdAfter, LocalDateTime createdBefore, Pageable pageable);
When trying to access the method in run time, I get the following error:
"Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'creationDate' expression specified as 'creationDate : Document{{$lt=2021-05-12T09:42:08.549}}'. Criteria already contains 'creationDate : Document{{$gt=2021-05-12T09:42:07.486}}'."
To solve this there was a need to change the Spring-Data method, and to use Between:
Page<Dog> findAllByCreationDateBetween(LocalDateTime createdAfter, LocalDateTime createdBefore, Pageable pageable);
**FOR MULTIPLE CRITERIA YOU CAN USE COMMA...
Query query = new Query(
Criteria.where("ip").is(ip)
.andOperator(
Criteria.where("createdDate").lt(endDate),
Criteria.where("createdDate").gte(startDate)
)
);**
db.getCollection('parentCollection').find({"mapObject.someField" : {$exists: true}})
i want this to convert into method like below
.
#Query("{mapObject.someField :{$exists : true}}")
List<Parent> findByMapKey(String id);
Here i am getting null pointer exception while running application
#Query("{mapObject.someField :{$exists : true}}")
here someField needs to be dynamic not fixed so i want my id to be passed in place of someField
Same question exists here as well
How to get parent object based upon key from child map in MongoRepository JAVA SpringBoot
It's not possible to do with MongoRepository. Instead, use MongoTemplate.
As mentioned above by #Valijon it is not possible with #Query annotation. Still if anyone finds a way please share. Following is how i achieved it using MongoTemplate
package com.somepackage.services;
import org.springframework.stereotype.Service;
import java.util.List;
import com.yourpackagestructure.Parent;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
#Service
public class Service{
private MongoTemplate mongoTemplate;
public Service(MongoTemplate mongoTemplate){
this.mongoTemplate = mongoTemplate;
}
public List<Parent> getParentList(String mapKey){
Query query = new Query();
query.addCriteria(Criteria.where("someMap." + mapKey).exists(true));
List<Parent> parents = mongoTemplate.find(query,Parent.class);
}
}
This question already has answers here:
Random documents from MongoDB using spring-data
(2 answers)
Closed 5 years ago.
Lets assume the following structure:
A user class:
public class User {
#Id
String id;
String name;
//...
}
The users repository:
public interface UserRepository extends MongoRepository<User, String> {
List<User> findByRandom(); // this method signature does not exist but would do what I intend to do
}
A user controller:
#Component
public class UserController {
private UserRepository users;
#Autowired
public UserController(
UserRepository users) {
this.users= users;
}
public List<User> getRandomUsers() {
return(users.findByRandom()); // limit is missing here
}
}
How would one achieve to receive random documents out of a structure like this.
Having a field with a random value on the document would not be a desired solution, since the values should always be random (e.g. if I hit the random int value 4 and receive the x following items, those would always be the same). Having to query x times is also not prefered, since this would be too heavy load.
Can anyone help?
Thanks in advance,
Codehai
Just use the $sample stage:
Via Spring-Data (from v2.0 onwards):
SampleOperation matchStage = Aggregation.sample(5);
Aggregation aggregation = Aggregation.newAggregation(sampleStage);
AggregationResults<OutType> output = mongoTemplate.aggregate(aggregation, "collectionName", OutType.class);
Directly through the Java driver:
import static com.mongodb.client.model.Aggregates.*;
users.aggregate(Arrays.asList(sample(5)));
I have a collection of documents called 'appointment', and I am trying to group together the number of appointments per day and populate an List of objects call AppointmentSummary, where there will be one object per day, I am using Spring boot to try and achieve this however I keep running into issues.
I have created the following three classes in the same package
AppointmentSummaryRepository.java
public interface AppointmentSummaryRepository extends
MongoRepository<Appointment,String>, AppointmentSummaryRepositoryCustom {
}
AppointmentSummaryRepositoryCustom.java
public interface AppointmentSummaryRepositoryCustom {
List<AppointmentSummary> aggregate(LocalDate startDate, LocalDate endDate);
}
AppointmentSummaryRepositoryImpl.java
public class AppointmentSummaryRepositoryImpl implements AppointmentSummaryRepositoryCustom {
private final MongoTemplate mongoTemplate;
private final Logger log = LoggerFactory.getLogger(AppointmentSummaryRepositoryImpl.class);
#Autowired
public AppointmentSummaryRepositoryImpl(MongoTemplate mongoTemplate){
this.mongoTemplate = mongoTemplate;
}
#Override
public List<AppointmentSummary> aggregate(LocalDate startDate, LocalDate endDate){
log.debug("This is a request to aggerate appointment summary between {} to {}", startDate.toString(), endDate.toString());
MatchOperation matchOperation = getMatchOperation(startDate, endDate);
GroupOperation groupOperation = getGroupOperation();
log.debug("End group operaton");
ProjectionOperation projectionOperation = getProjectOperation();
return mongoTemplate.aggregate(Aggregation.newAggregation(
matchOperation,
groupOperation,
projectionOperation
), Appointment.class, AppointmentSummary.class).getMappedResults();
}
private MatchOperation getMatchOperation(LocalDate startDate, LocalDate endDate) {
log.debug("Begin Match Operation");
Criteria appointmentCriteria = where("appointment_date").gt(startDate).andOperator(where("appointment_date").lt(endDate));
log.debug("End Match Operation");
return match(appointmentCriteria);
}
private GroupOperation getGroupOperation() {
log.debug("Performing Group Operation");
return group("appointment_date")
.last("appointment_date").as("appointment_date")
.addToSet("id").as("appointmentIds")
.sum("id").as("count");
}
private ProjectionOperation getProjectOperation() {
log.debug("Begin project operation");
return project("appointment_date","appointmentIds","count")
.and("appointment_date").previousOperation();
}
Whenever I run the it, I keep getting the following error:
org.springframework.data.mapping.PropertyReferenceException: No property appointment found for type Appointment!
I believe the issue is happening in the following code segment, my understanding is that I initialize the different stages of the pipeline and pass them to the mongoTemplate and the 'getMappedResults' will map the fields from the two objects and populate the AppointmentSummary.class with the output of the aggregation pipeline?
return mongoTemplate.aggregate(Aggregation.newAggregation(
matchOperation,
groupOperation,
projectionOperation
), Appointment.class, AppointmentSummary.class).getMappedResults();
To note that the object Appointment does not have a field/property appointment. I added this in but when I ran the code I received another error message complaining of cannot find type date for Appointment.
Thanks in advance for your help!
Use below variant of mongo template aggregate which takes collection name instead of class.
mongoTemplate.aggregate(Aggregation.newAggregation(
matchOperation,
groupOperation,
projectionOperation
), "appointment", AppointmentSummary.class).getMappedResults();
The reason was that when you use typed variant spring runs validation on the fields used in the aggregation pipeline to match the field names in the pojo and fails when it doesn't find the alias.