问题
I need help in writing mongodb aggregation pipeline in spring.
Here is a sample of my data on which I want to execute the query (Please note that the following data is a result of Match aggregation pipeline in spring which has conditions for the eventDate to match the range and eventName equals to 'A'):
{
"_id": ObjectId("1234567890"),
"eventDate": ISODate("2017-01-29T03:56:04.297Z"),
"eventName": "A"
}
{
"_id": ObjectId("1234567890"),
"eventDate": ISODate("2017-01-29T03:57:04.887Z"),
"eventName": "A"
}
{
"_id": ObjectId("1234567890"),
"eventDate": ISODate("2017-01-29T04:05:00.497Z"),
"eventName": "A"
}
Now I want to write the Group aggregation pipeline on eventDate field where it should group on Year,Month, Day and Hour because what I'm looking for is hourly data.
Sample of the result I want it to look like which projects only eventDate and eventName fields:
{
"eventDate": ISODate("2017-01-29T03:00:00.000Z"),
"eventName": "A"
}
{
"eventDate": ISODate("2017-01-29T04:00:00.000Z"),
"eventName": "A"
}
So if you notice above that the data is in a group of hours and apart from that Minutes and seconds are now set to 0.
I tried this solution but didn't work for me: MongoTemplate aggregate - group by date
Any kind of help appreciated. Thanks in advance.
回答1:
You can use date arithmetic here to get the date time with minute, second and milliseconds part reset to 0.
You may need to make some adjustment based on your spring mongo version and java version.
Version : Mongo 3.2, Spring Mongo 1.9.5 Release and Java 8
Mongo Shell Query:
db.collection.aggregate(
[{
$group: {
_id: {
$subtract: ["$eventDate", {
$add: [{
$multiply: [{
$minute: "$eventDate"
}, 60000]
}, {
$multiply: [{
$second: "$eventDate"
}, 1000]
}, {
$millisecond: "$eventDate"
}]
}]
},
eventName: {
$addToSet: "$eventName"
}
}
}]
)
Spring Code:
AggregationOperation group = context -> context.getMappedObject(new BasicDBObject(
"$group", new BasicDBObject(
"_id",
new BasicDBObject(
"$subtract",
new Object[]{
"$eventDate",
new BasicDBObject("$add",
new Object[]{
new BasicDBObject("$multiply",
new Object[]{new BasicDBObject("$minute", "$eventDate"), 60000}),
new BasicDBObject("$multiply",
new Object[]{new BasicDBObject("$second", "$eventDate"), 1000}),
new BasicDBObject("$millisecond", "$eventDate")
}
)
}
)
).append("eventName", new BasicDBObject("$addToSet", "$eventName"))));
Update: Using $project
db.collection.aggregate(
[{
$project: {
eventDate: {
$subtract: ["$eventDate", {
$add: [{
$multiply: [{
$minute: "$eventDate"
}, 60000]
}, {
$multiply: [{
$second: "$eventDate"
}, 1000]
}, {
$millisecond: "$eventDate"
}]
}]
},
eventName: 1
}
}, {
$group: {
_id: "$eventDate",
eventName: {
$addToSet: "$eventName"
}
}
}]
)
Spring Code
AggregationOperation project = context -> context.getMappedObject(new BasicDBObject(
"$project", new BasicDBObject(
"eventDate",
new BasicDBObject(
"$subtract",
new Object[]{
"$eventDate",
new BasicDBObject("$add",
new Object[]{
new BasicDBObject("$multiply",
new Object[]{new BasicDBObject("$minute", "$eventDate"), 60000}),
new BasicDBObject("$multiply",
new Object[]{new BasicDBObject("$second", "$eventDate"), 1000}),
new BasicDBObject("$millisecond", "$eventDate")
}
)
}
)
).append("eventName", 1)));
AggregationOperation group = Aggregation.group("eventDate").addToSet("eventName").as("eventName");
Aggregation agg = Aggregation.newAggregation(project, group);
来源:https://stackoverflow.com/questions/42011355/how-to-write-mongodb-aggregation-group-pipeline-on-part-of-date-timeyear-month