Spring JPA Mongo Datediff operator - java

I am trying to convert a native mongo query to jpa.
The basis is that I have to subtract two dates that are in string format, that is, first I have to convert and then use datediff, this is how I get the result I want from my compass client:
$project: {
waiting: {
$dateDiff: {
startDate: {
$toDate: "$date_start"
},
endDate: {
$toDate: "$date_end"
},
unit: "second"
}
}
_id: 0
}
In the documentation there is a reference to the use of datediff but I don't see any example and I'm somewhat new to this technology
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.aggregation
(Date Aggregation Operators)
this has been the closest I have come, giving a failed result because the dates are not in date format
ProjectionOperation projectStage = Aggregation.project("test").andExpression("date_start - date_end").as("test");
error during aggregation :: caused by :: can't $subtract string from string"

Related

How to sum sizes of arrays in MongoDB Java driver?

I have documents similar to below in my People collection:
{
"_id":{"$oid": XYZ},
"id": {"$numberLong":"1"},
"name":"XYZ",
"friends": [...],
"likes": [...]
}
I want to count sum of sizes of friends and likes array for each of document. In MongoDB I created an aggregation query:
{"$project":
{
id: "$id",
neighbour_count: {$sum: [{$size: "$likes"}, {$size: "$friends"}]}
}
}
and got results:
{
"_id": XYZ,
"id":2,
"neighbour_count":1601
}
Now I want simmilar results in my Java MongoDB driver. I tried to do something with Aggregates.count and Projections.fields, but didn't get proper results.
My current code:
DBCollection peopleCollection = database.getCollection("People");
BasicDBList sum = new BasicDBList();
sum.add(new BasicDBObject("$size", "$likes"));
sum.add(new BasicDBObject("$size", "$friends"));
Iterable<DBObject> output = peopleCollection.aggregate(Arrays.asList(
new BasicDBObject("$project", new BasicDBObject("id","$id").append("$sum", sum))))
.results();
throws error:
Invalid $project :: caused by :: FieldPath field names may not start with '$'.
How to do it in proper way?

How to code "generatedDate: new Date()" with Spring Data MongoDB Java API?

I need help with Spring Data Java API. I am writing aggregation pipeline for the report. The last stage is "$project" where I set the data for output. In Mongodb shell the pipeline works just fine but I can't find the way to code "generatedDate: new Date()" with Spring Data SDK for MongoDB.
Here is how the "$project" should look like:
{$project: {
coach: {
firstName: '$coach.firstName',
lastName: '$coach.lastName',
employeeId: '$coach._id'
},
patient: {
firstName: '$patientContact.patient.firstName',
lastName: '$patientContact.patient.lastName',
contactId: '$patientContact._id'
},
customerName: '$patientContact.organization.name',
coachingSummary: 1,
formCreatedDate: 1,
generatedDate: new Date() //<<--- This is what I want
}}
I want the server to generate new Date instance and return it in the response.
Here is my Java code for this aggregation stage:
ProjectionOperation finalProject = project("coachingSummary", "formCreatedDate")
.and("$patientContact.organization.name").as("customerName")
.and("coach")
.nested(Fields.from(
Fields.field("firstName", "coach.firstName"),
Fields.field("lastName", "coach.lastName"),
Fields.field("employeeId", "coach._id")
))
.and("patient")
.nested(Fields.from(
Fields.field("firstName", "patientContact.patient.firstName"),
Fields.field("lastName", "patientContact.patient.lastName"),
Fields.field("contactId", "patientContact._id")
))
.and("<SOMETHING_GOES_HERE>").as("generatedDate");//<<-- How to code it?

How to combine "not" operators using the spring data Criteria builder

To setup the scene, the query I want to produce is similar to the following that I've manually written. The idea is that I want to exclude a date range from the result set. In this case, nothing from today, but if there's any in the past or in the future, I want them!
{
"createdOn": {
$not: {
"$lte": ISODate("2020-20-23T23:59:59.999999999"),
"$gte": ISODate("2020-20-23T00:00"),
}
}
}
The code I am using to try and get the above is the following:
Criteria.where("createdOn")
.not()
.gte(LocalDate.now().atTime(LocalTime.MIN))
.lte(LocalDate.now().atTime(LocalTime.MAX))
However, that generates the following:
{
"createdOn": {
"$not": {
"$gte": {
"$java": "2020-03-23T00:00"
}
},
"$lte": {
"$java": "2020-03-23T23:59:59.999999999"
}
}
}
If I changed the code to add another not before the lte it still produces the same output.
Is there any way of producing the query I want, or an alternate way of excluding a range of dates from the result set?
I tried your mongo shell and the MongoDB Spring Java code. The shell code works fine, but the corresponding Java code using the not() doesn't work (I don't know why).
Here is another way working with the same functionality your looking for:
...nothing from today, but if there's any in the past or in the future
I am using the following input documents:
{ _id: 1, createdOn: ISODate("2020-03-21T12:05:00") },
{ _id: 2, createdOn: ISODate("2020-03-28T18:33:00") },
{ _id: 3, createdOn: ISODate("2020-03-24T01:56:00") }
And, assuming today's date: ISODate("2020-03-24T02:50:04.992Z"), the result should exclude the document with _id: 3, where the createdOn is within today.
The mongo shell query:
db.collection.find( {
$or: [
{ createdOn: { $gt: ISODate("2020-03-24T23:59:59.99") } },
{ createdOn: { $lt: ISODate("2020-03-24T00:00:00") } }
]
} )
This returns the documents with _id's 1 and 2 (these exclude today's date).
The corresponding Java code:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd H:m:s");
Date fromDate = dateFormat.parse("2020-03-24 00:00:00");
Date toDate = dateFormat.parse("2020-03-24 23:59:59");
Criteria c = new Criteria().orOperator(
Criteria.where("createdOn").lt(fromDate),
Criteria.where("createdOn").gt(toDate) );
Query q = Query.query(c);
MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "testDB");
List<Document> result = mongoOps.find(q, Document.class, "collection");
result.forEach(doc -> System.out.println(doc.toJson()));

MongoDB ISODate parse with Spring Data

I am using MongoDB 3 and I'm trying to get all purchases by day. The problem is that I have the following value in mongo:
"createDate" : ISODate("2016-04-11T17:57:12.960Z")
And I want to get all the purchases using the following date format dd/MM/yyyy. This is my method:
public List<Purchase> getPurchasesByDate(BigInteger company, Date date, PurchaseStatus status) {
Query query = new Query();
query.addCriteria(Criteria.where("createDate").lte(date).and("status").is(status.toString()).and("company").is(company.toString()));
return mongoTemplate.find(query, Purchase.class);
}
This is what I seeing into mongo console:
{ "createDate" : { "$lte" : { "$date" : "2016-04-11T19:14:56.322Z"} } , "status" : "PAYED" , "company" : "1"}
Obviously is not returning any values. I'm calling my method like this getPurchasesByDate(1, new Date(), PurchaseStatus.PAYED).
Does anybody knows how can I can get all documents by date using this format dd/MM/yyyy?
thanks

Create aggregation in mongodb with spring

I have aggregation that works in mongo and i need to create the exact one in java with spring. I didn't find a way. Do you know if there is one?
db.collection_name.aggregate([
{
$group: {
_id : {
year : {$year : "$receivedDate" },
month : {$month: "$receivedDate"},
day : { $dayOfMonth : "$receivedDate"}
},
count : { $sum: 1 }
}
}
])
You could try projecting the fields first by using the SpEL andExpression in the projection operation and then group by the new fields in the group operation:
Aggregation agg = newAggregation(
project()
.andExpression("year(receivedDate)").as("year")
.andExpression("month(receivedDate)").as("month")
.andExpression("dayOfMonth(receivedDate)").as("day"),
group(fields().and("year").and("month").and("day"))
.count().as("count")
);

Categories