How to write Mongodb aggregation group pipeline on part of Date/Time(Year, month, day, hour) in Spring?

╄→尐↘猪︶ㄣ 提交于 2019-12-12 04:25:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!