After upgrading from Spring boot 2.2.6.RELEASE to 2.4, the following mapping does not work & returns null for all the mapped values. I'm unable to find any mongo documentation describing any update to aggregation or mapping. However the rawResults contains the required data. I've tried changing the mongo versions, spring boot version upgrades.
The same code works without a issue in spring boot 2.2.6.RELEASE version.
final Aggregation agg = newAggregation(match(Criteria.where("id.cid").is(cId)),
group("sId.assignmentId", "status").count().as("total"),
sort(Sort.Direction.DESC, "sId.assignmentId", "status"));
final AggregationResults<StatusSummeryDTO> groupResults = mongoTemplate.aggregate(agg,
Submission.class, StatusSummeryDTO.class);
return groupResults.getMappedResults();
Turns out after MongoDB driver version being changed from 3.x to 4.x in the result DTO class we will need to specify the exact field value using #Field annotation. Unlike in 3.x it does not map automatically which resulted in the above issue.
Since there are breaking changes in the aggregation when moving from 3.x to 4.x I thought that might be the issue. to be on the better side I've changed my code to be compatible with 4.x using new classes as follows.
MatchOperation match = match(Criteria.where("id.cid").is(cId));
GroupOperation group = group("sId.assignmentId", "status").count().as("total");
SortOperation sort = sort(Sort.Direction.DESC, "sId.assignmentId", "status");
Aggregation agg = newAggregation(match, group, sort);
AggregationResults<StatusSummeryDTO> groupResults = mongoTemplate.aggregate(agg, Submission.class, StatusSummeryDTO.class);
return groupResults.getMappedResults();
Related
Consider a aggregation, which is formed like:
MatchOperation matchOperation = match(Criteria.where("group").is("A")
.andOperator(Criteria.where("score").lt(50))) ;
SortOperation sortOperation = sort(Sort.by(Direction.DESC, "department"));
Aggregation aggregation = Aggregation.newAggregation(matchOperation, sortOperation) ;
I want to issue a bulk remove (or basically remove each document found as a result of above) using a Spring Boot application.
Problem:
Unable to find a suitable method to do so, and I want to achieve this using Aggregation only ie. don't want to switch to Query.
What I've tried already:
I have already tried using mongoTemplate.findAllAndRemove(), but it accepts a Query and I am using Aggregation.
I have also tried using
BulkOperations bulkOps = mongoTemplate.bulkOps(BulkMode.ORDERED, EntityName.class) ;
And then, bulkOps.remove() but this method also accepts a List<Query>
You can't remove using aggregation so I think there are two options:
Using your aggregate query to get all _ids and do a new Query to remove these _ids.
Something like this (not tested):
List<Document> result = mongoTemplate.aggregate(aggregation, "my_collection", Document.class).getMappedResults();
List<ObjectId> resultList = result.stream().map(item -> item.get("_id")).collect(Collectors.toList());
mongoTemplate.remove(new Query(Criteria.where("_id").in(resultList)), YourClass.class);
Create a new delete query. As you need to use delete maybe you can avoid aggregation simply using this:
mongoTemplate.remove(new Query(Criteria.where("group").is("A").andOperator(Criteria.where("score").lt(50))), YourClass.class);
Note that the criteria is the same as you have in the match. This is because is the same use it in a find/remove/update query and into an aggregation query
By the way, I don't understand why sort if you want to delete.
I have a paginated API backed by an Aggregation with a $geoNear pipeline step.
In Mongo versions before 4.2, $geoNear aggregations had a default limit of 100.
To avoid this, it was possible to set the num field to a large number for the NearQuery.
Query query = new Query();
...
NearQuery nearQuery = NearQuery.near(...);
nearQuery.query(query);
//force the geoNear operation to return more than 100 results
nearQuery.num(Integer.MAX_VALUE);
List<AggregationOperation> steps = Lists.newArrayList(geoNear(nearQuery, "distance"));
//add skip and limit operations to mimic pagination functionality
steps.add(skip(pageable.getPageNumber() * pageable.getPageSize()));
steps.add(limit(pageable.getPageSize()));
Aggregation agg = Aggregation.newAggregation(steps);
...
In Mongo version 4.2, the num field has been removed as well as the limit of 100 results (described here in the first note). In response to this, GeoNearOperation.java has been updated in spring-data-mongodb to remove the num field.
Now, I would understand that if I were to connect to a MongoDb server running version 4.2 everything would work as is (disclaimer: I have not tried this.) However, I'm running version 4.0.5 locally and version 3.6.12 in production. Using spring-boot-starter-data-mongodb with version 2.1.13.RELEASE the above code works and paginated results are returned past 100 results. Upgrading to 2.2.0.RELEASE causes the above Aggregation to no longer return past 100 results.
How am I supposed to query a MongoDB database on a version older than 4.2 with the 2.2.X branch of
spring-data-mongodb if the num field is always removed?
yes try using mongoTemplate. It should work
Point point = new Point(51.4678685, -0.0860632);
List<Pub> venues =
mongoTemplate.find(new Query(Criteria.where("location").near(point).maxDistance(0.01)), Pub.class);
further refer
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#reference
I have a requirement where i need to use distinct with skip and limit and i have googled a lot for this but found nothing useful and as per some answers it is not supported with old version spring data mongodb and in the newer version is there any way to use this or is there any solution to achieve distinct with skip and limit with aggregation framework
I have not added distinct but used skip, limit with aggregation
Aggregation agg = newAggregation(match(Criteria.where("goalId").is(goal.getId())), skip((long) request.getPage() * request.getSize()),limit(request.getSize()));
final AggregationResults<ActivityHistory> results = mongoOperations.aggregate(agg, ActivityHistory.class, ActivityHistory.class);
List<ActivityHistory> activityHistoryList = results.getMappedResults();
Is there a way to return a cursor with spring data's mongodb aggregation?
Aggregation agg = newAggregation(
match(Criteria.where("_id").is(objId)),
unwind("taskResultContent"),
project("taskResultContent.executionUUID","taskResultContent.returnContent","taskResultContent.sequency").and("resultID").previousOperation(),
match(Criteria.where("executionUUID").is(executionUUID)),
sort(DESC,"sequency")
).withOptions(Aggregation.newOptions().cursor(cursor).build());
Solution
Quoting here :
From spring-data-mongo version 2.0.0.M4 onwards (AFAIK) MongoTemplate got an aggregateStream method.
So you can do the following:
AggregationOptions aggregationOptions = Aggregation.newAggregationOptions()
// this is very important: if you do not set the batch size,
// you'll get all the objects at once and you might run out of memory
// if the returning data set is too large
.cursorBatchSize(mongoCursorBatchSize)
.build();
data = mongoTemplate.aggregateStream(Aggregation.newAggregation(
Aggregation.group("person_id")
.count()
.as("count"))
.withOptions(aggregationOptions), collectionName, YourClazz.class);
Spring data for mongodb does not support the use of a cursor when aggregating. The MongoDB java driver must be used instead.
I was looking to use the $natural operator in Spring Data MongoDB, as documented here:
https://docs.mongodb.org/v3.0/reference/operator/meta/natural/
Is this possible to do using the MongoTemplate class? Thanks.
It is possible to use $natural in at least three styles where 1. and 2. are probably what you're looking for:
1. Using Sort with Query
Query query = new Query().with(new Sort(Direction.ASC, "$natural"));
use the query afterwards with MongoTemplate. The query carries a sort document like:
{ "$natural" : 1}
2. Using BasicQuery
BasicQuery allows using own DBObjects for the query document, the fields ("projection") and sorting.
BasicQuery basicQuery = new BasicQuery(new BasicDBObject());
basicQuery.setSortObject(new BasicDBObject("$natural", 1));
3. Using execute and CollectionCallback
This is the most extensive way in which you're getting access to the DBCollection and you can use the native MongoDB driver API. See Spring Data Mongo docs for more details.