Spring Data mongodb: 'year' must evaluate to an integer - spring

I've built this aggregation:
ProjectionOperation projectStage = Aggregation
.project("application", "uploadedRefs", "uploadedKb", "downloadedDocs", "downloadedKb")
.and(DateOperators.Year.yearOf("timestamp")).as("year")
.and(DateOperators.Month.monthOf("timestamp")).as("month")
.and(DateOperators.DayOfMonth.dayOfMonth("timestamp")).as("day")
.and(DateOperators.DateFromParts.dateFromParts()
.yearOf("timestamp")
.monthOf("timestamp")
.dayOf("timestamp")
).as("startIntervalTimestamp");
Aggregation aggregation = Aggregation
.newAggregation(
projectStage
);
System.out.println(aggregation.toString());
The output is:
[
{
"$project":{
"application":1,
"uploadedRefs":1,
"uploadedKb":1,
"downloadedDocs":1,
"downloadedKb":1,
"year":{
"$year":"$timestamp"
},
"month":{
"$month":"$timestamp"
},
"day":{
"$dayOfMonth":"$timestamp"
},
"startIntervalTimestamp":{
"$dateFromParts":{
"year":"timestamp",
"month":"timestamp",
"day":"timestamp"
}
}
}
}
]
The error message is:
Error: command failed: {
"ok" : 0,
"errmsg" : "'year' must evaluate to an integer, found string with value \"timestamp\"",
"code" : 40515,
"codeName" : "Location40515"
}

Solved:
Field timestampField = Fields.field("timestamp");
ProjectionOperation projectStage = Aggregation
.project("application", "uploadedRefs", "uploadedKb", "downloadedDocs", "downloadedKb")
.and(DateOperators.Year.year(timestampField)).as("year")
.and(DateOperators.Month.month(timestampField)).as("month")
.and(DateOperators.DayOfMonth.dayOfMonth(timestampField)).as("day")
.and(DateOperators.DateFromParts.dateFromParts()
.year(DateOperators.Year.year(timestampField))
.month(DateOperators.Month.month(timestampField))
.day(DateOperators.DayOfMonth.dayOfMonth(timestampField))
).as("startIntervalTimestamp");

Related

Spring Data Mongo: Compare Two Dates in the Same Document

A brief overview of the document I am working with:
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
#Data
#SuperBuilder(toBuilder = true)
public class BreachBrand {
#Id
private String id;
#CreatedDate
#Field("created_date")
#DiffIgnore
private Instant createdDate;
#LastModifiedDate
#Field("last_modified_date")
#DiffIgnore
private Instant lastModifiedDate;
}
What I am trying to do is compare the lastModifiedDate to the createdDate. So I created a criteria object like so:
criteria.add(Criteria.where("last_modified_date").gt("ISODate('created_date')"));
I've also tried:
criteria.add(Criteria.where("last_modified_date").gt("created_date"));
which is then used in the match operation of an Aggregation object. Using the first criteria code snippet, the aggregation looks like this:
{ "aggregate" : "__collection__", "pipeline" : [{ "$lookup" : { "from" : "brands", "localField" : "brand_dfp_id", "foreignField" : "dfp_id", "as" : "brand"}}, { "$match" : { "$and" : [{ "last_modified_date" : { "$gt" : "ISODate('created_date')"}}]}}, { "$sort" : { "date" : -1}}, { "$skip" : 0}, { "$limit" : 25}], "allowDiskUse" : true, "collation" : { "locale" : "en", "strength" : 1}}
The mongoTemplate object executes the aggregate method w/o error but no records are returned.
I'm suspecting that the gt(Object o) method is expecting an object that is an actual value to use to compare against. All is good when I use an actual date:
criteria.add(Criteria.where("last_modified_date").gt(Instant.parse("2019-05-18T17:07:25.333+00:00")));
As an interesting aside the following works in mongoshell:
db.breaches.find({$where: "this.last_modified_date>this.created_date"}).pretty();
And the following works in Compass (but the export to language button will not display the output):
/**
* $match operation
*/
{
last_modified_date: {$gt: ISODate('created_date')}
}
EDIT:
It appears I need to use a projection to determine if last_modified_date is greater than created date. I got this to work in compass:
[{
$project: {
greater: {
$gt: [
'$last_modified_date',
'$created_date'
]
},
doc: '$$ROOT'
}
}, {
$match: {
greater: true
}
}]
I'm having issues moving that into a projection though:
ProjectionOperation projectionOperation = project("last_modified_date", "created_date").andExpression("$gt", "$last_modified_date", "$created_date").as("greater");
I've also tried this:
ProjectionOperation projectionOperation = project("last_modified_date", "created_date").andExpression("$gt", Arrays.asList("$last_modified_date", "$created_date")).as("greater");
Results in an exception when creating the aggregation:
Aggregation aggregation = newAggregation(
lookup("brands", "brand_dfp_id", "dfp_id", "brand"),
projectionOperation,
matchOperation, //Criteria.where("greater").is(true)
sortOperation,
skipOperation,
limitOperation
)
.withOptions(AggregationOptions.builder()
.allowDiskUse(true)
.collation(Collation.of("en").strength(Collation.ComparisonLevel.primary())).build());
exception:
java.lang.IllegalArgumentException: Invalid reference 'date'!
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:114)
at org.springframework.data.mongodb.core.aggregation.ExposedFieldsAggregationOperationContext.getReference(ExposedFieldsAggregationOperationContext.java:86)
at org.springframework.data.mongodb.core.aggregation.SortOperation.toDocument(SortOperation.java:74)
at org.springframework.data.mongodb.core.aggregation.AggregationOperation.toPipelineStages(AggregationOperation.java:55)
at org.springframework.data.mongodb.core.aggregation.AggregationOperationRenderer.toDocument(AggregationOperationRenderer.java:56)
at org.springframework.data.mongodb.core.aggregation.AggregationPipeline.toDocuments(AggregationPipeline.java:77)
at org.springframework.data.mongodb.core.aggregation.Aggregation.toPipeline(Aggregation.java:705)
at org.springframework.data.mongodb.core.AggregationUtil.createPipeline(AggregationUtil.java:95)
at org.springframework.data.mongodb.core.MongoTemplate.doAggregate(MongoTemplate.java:2118)
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:2093)
at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1992)

Spring MongoDB : querying documents with two equal fields

I want to query that returns document that two fields of it are equal
I found mongodb raw query from this question :
db.coll.find({ $where : "this.field1 == this.field2" } );
How can I perform it with spring criteria:
criteria = criteria.andOperator(
Criteria.where("successfulSent").is("true"),
Criteria.where("this.fieldOne == this.fieldTwo"));
but its not working beacuse generated query become :
{ ... "$and" : [ { "successfulSent" : "true"} , { "this.fieldOne == this.fieldOne " : { }}]}
You can try on this way:
Criteria.where("$where").is("this.field1 == this.field2")
Query toString() will be:
Query: { "$where" : "this.cts == this.uts"}, Fields: null, Sort: null

In Spring boot Mongodb find group by count by using Aggregation framework

Hi a am try to do rest api in spring boot with mongodb to find group by count the input data look like. please share any logic, code, example link.
guys i am expecting spring boot logic. how mongodb aggregation framework integrating.
{
"_id" : "PRODUCT_01",
"productname" : "product1",
"value" : "codesoft"
},
{
"_id" : "PRODUCT_01",
"productname" : "product2",
"value" : "codesoft"
},
{
"_id" : "PRODUCT_01",
"productname" : "product1",
"value" : "codesoft"
}
expected output
{
product1 : 2,
product2 : 1
}
Any help is appreciated.
try this
db.testColln.aggregate(
{
$group : {_id : "$productname", total : { $sum : 1 }}
}
);
for Spring Boot
Aggregation agg = newAggregation(
group("productname").count().as("total")
project("productname").and("total"),
);
AggregationResults<Product> groupResults
= mongoTemplate.aggregate(agg, Product.class,Result.class);
List<Result> result = groupResults.getMappedResults();
public class Result {
private String productname;
private long total;
}
#GetMapping("/group")
public List<ProductCount> groupByName() {
// grouping by prductName
GroupOperation groupOperation =
Aggregation.group("productName").count().as("count");
// projection operation
ProjectionOperation projectionOperation =
Aggregation.project("count").and("productName").previousOperation();
// sorting in ascending
SortOperation sortOperation =
Aggregation.sort(Sort.by(Sort.Direction.ASC, "count"));
// aggregating all 3 operations using newAggregation() function
Aggregation aggregation =
Aggregation.newAggregation(groupOperation,projectionOperation
,sortOperation);
// putting in a list
// "products" is collection name
AggregationResults<ProductCount> result =
mongotemplate.aggregate(aggregation, "products",
ProductCount.class);
return result.getMappedResults();
}
$ make ProductCount class in model package
public class ProductCount {
private String productName;
private int count;
#getters
#setters

Spring MongoDB BasicQuery not working with projection

I have following BasicQuery
BasicQuery query2 = new BasicQuery("{status:{$in:['APPROVED','NEW','OPEN']}},{siteId:1,_id:0}");
Where BasicQuery is a class from SpringData mongoDb org.springframework.data.mongodb.core.query.BasicQuery. While doing the debug the above query get compiled into
Query: { "status" : { "$in" : [ "APPROVED" , "NEW" , "OPEN"]}}, Fields: null, Sort: { }
But it should have been compiled as below
Query: { "status" : { "$in" : [ "APPROVED" , "OPEN" , "NEW"]}}, Fields: { "siteId" : 1 , "_id" : 0}, Sort: null
If you notice, fields are still missing into compiled BasicQuery. Please help how i can have project in BasicQuery. I can have projection by using Query as below.
Query query = new Query();
query.addCriteria(Criteria.where(STATUS).in(validStatus));
query.fields().include("siteId").exclude("_id");
My query is how i can achieve the same using BasicQuery.
I guess i got the answer. Instead of using single string argument constructor of BasicQuery we need to use two String argument basic query as follow.
BasicQuery query2 = new BasicQuery("{status:{$in:['APPROVED','NEW','OPEN']}}","{siteId:1,_id:0}");
Above will compile into following query
Query: { "status" : { "$in" : [ "APPROVED" , "OPEN" , "NEW"]}}, Fields: { "siteId" : 1 , "_id" : 0}, Sort: null
BasicQuery query = new BasicQuery("{ $and: [{ studentId: { $in: "+studentIds+" } }, { status: { $ne: '"+studStatus+"'} }] }");
studentIds is an array and studStatus is a string!
Thanks to vashishth

missing type in composite literal in golang/mongodb aggregate query

I want to write mongo query in golang. my mongo query is -
aggregate([
{$match: {$and :
[
{"stream" : "CS"},
{"semester" : "sem3"},
{"section" : "A"}
]
}},
{$unwind: '$atndnc'},
{ $group: { _id:{rollno: "$atndnc.rollno",attend:"$atndnc.attend"},count: { $sum: 1 }}},
{ $project:
{ _id: '$_id.rollno',
'attend' : '$_id.attend',
'count' : '$count'
}}
])
And my Go code is -
cond:=[]bson.M{
bson.M{"$match": bson.M{"$and ":[]interface{}{
bson.M{"stream" : srchobj.Stream},
bson.M{"semester" : srchobj.Semester},
bson.M{"section" : srchobj.Section},
bson.M{"college_id":srchobj.College_id},
bson.M{"date":bson.M{"$gt":srchobj.Startdate,"$lt":srchobj.Enddate}}}}},
bson.M{"$unwind": "$atndnc"},
bson.M{"$group":bson.M{"_id":{"rollno":bson.M{"$atndnc.rollno"},"attend":bson.M{"$atndnc.attend"}},"count":bson.M{"$sum":1}}},
bson.M{"$project":bson.M{"_id":"$_id.rollno","count":"$_id.count"}}}
but it give the error "missing type in composite literal" in
bson.M{"$group":bson.M{"_id":{"rollno":bson.M{"$atndnc.rollno"},"attend":bson.M{"$atndnc.attend"}},"count":bson.M{"$sum":1}}},
in this line.what should i do now?
You have a missing type declaration on a set of braces in your $group query:
{"rollno":bson.M{"$atndnc.rollno"},"attend":bson.M{"$atndnc.attend"}}
I would assume should be:
bson.M{"rollno":bson.M{"$atndnc.rollno"},"attend":bson.M{"$atndnc.attend":nil}}
there are also a few other initialization things like initializations with just a string key (remember, a bson.M is just an alias for map[string]interface{}
Thanks for your support.I got the desired output by doing this.
cond :=[]bson.M{
bson.M{"$match": bson.M{
"stream" : srchobj.Stream,
"semester" : srchobj.Semester,
"section" : srchobj.Section,
"college_id":srchobj.College_id,
"date":bson.M{
"$gt":srchobj.Startdate,
"$lt":srchobj.Enddate},
},
},
bson.M{"$unwind": "$atndnc"},
bson.M{"$group":bson.M{
"_id":bson.M{
"rollno":"$atndnc.rollno",
"attend":"$atndnc.attend",
"name":"$atndnc.name",
},
"count":bson.M{"$sum":1},
},
},
bson.M{"$project":bson.M{
"rollno":"$_id.rollno",
"name":"$_id.name",
"count":"$count",
"attend":"$_id.attend",
},
},
bson.M{"$sort":bson.M{"rollno":1}},
}

Resources