Analog for group concat in sql

这一生的挚爱 提交于 2019-12-20 03:28:06

问题


In an aggregation process I've got this data:

{
    "_id" : "billing/DefaultController/actionIndex",
    "min_time" : 0.033,
    "max_time" : 5.25,
    "exec_time" : 555.490999999997,
    "qt" : 9059,
    "count" : 2,
    "date" : [ 
        ISODate("2014-02-10T00:00:00.000Z"), 
        ISODate("2014-02-11T00:00:00.000Z")
    ]
},

How to change my query:

db.page_speed_reduced.aggregate([
    {$group: {
        _id: "$value.route",
        min_time: {$min: "$value.min_time"},
        max_time: {$max: "$value.max_time"},
        exec_time: {$sum: "$value.exec_time"},
        qt: {$sum: "$value.qt"},
        count: {$sum: NumberInt(1)},
        date: {$push: "$_id.date"},
    }}
]);

for getting "$date" as concatenated string:

2014-02-10, 2014-02-11

UPDATE:

I tried this variant, but mongodb generated the error:

db.page_speed_reduced.aggregate([
    {$group: {
        _id: "$value.route",
        min_time: {$min: "$value.min_time"},
        max_time: {$max: "$value.max_time"},
        exec_time: {$sum: "$value.exec_time"},
        qt: {$sum: "$value.qt"},
        count: {$sum: NumberInt(1)},
        date: {$push: "test sting"},
    }},
    {$project: {
        'date': {$concat: ['$date']}
        //'date': {$concat: '$date'} //some error
    }}
]);

uncaught exception: aggregate failed: {
 "errmsg" : "exception: $concat only supports strings, not Array",
 "code" : 16702,
 "ok" : 0
}
'date': {$concat: '$date'}

回答1:


As per comments so far it is unclear what you are grouping or what you want as the end result, other than to say that you want to get your dates concatenated into something like "just the day" with no hours or minutes together. Presumably you want those distinct days for some purpose.

There are various Date Operators in the pipeline you can use on dates, and the is the $concat operator as well. Unfortunately all of the Date Operators produce an integer as their result, and for the sort of Date string you want, $concat will only work with strings. The other problem being that you cannot cast the integer into a string type within aggregation.

But you can use sub-documents, here we'll just work with the date:

db.record.aggregate([
    // Unwind the array to work with it
    {$unwind: "$date"},

    // project into our new 'day' document
    {$project:{ 
        day: { 
            year: {$year: "$date"},
            month: {$month: "$date"}, 
            day: {$dayOfMonth: "$date"}
        }
     } },

     // optionalally sort if date order is important [ oldest -> newest ] 
     {$sort: { "day.year": -1, "day.month": -1, "day.day": -1}},

     // Wind back unique values into the array
     {$group: {_id:"$_id", days: {$addToSet: "$day"} }}
])

So, it's not a string, but it can easily be post-processed into one, but most importantly it's grouped and sortable.

The principles remain the same if you want the unique dates this way as an array at the end or whether you want to group totals by those dates. So primarily keep in mind the $unwind and $project parts using the date operators.

--EDIT--

With thanks to the community as shown in this post there is this undocumented behavior of $substr, in which integers can be cast as strings.

db.record.aggregate([
    // Unwind the array to work with it
    {$unwind: "$date"},

    // project into our new 'day' document
    {$project:{ 
        day: { 
            year: {$year: "$date"},
            month: {$month: "$date"}, 
            day: {$dayOfMonth: "$date"}
        }
     } },

     // optionalally sort if date order is important [ oldest -> newest ] 
     {$sort: { "day.year": -1, "day.month": -1, "day.day": -1}},

     // now we are going to project to a string ** magic @heinob **
     {$project: { 
         day: {$concat: [
             {$substr: [ "$day.year", 0, 4 ]},
             "-",
             {$substr: [ "$day.month", 0, 2 ]},
             "-",
             {$substr: [ "$day.day", 0, 2 ]}
         ]}
     }},

     // Wind back unique values into the array
     {$group: {_id:"$_id", days: {$addToSet: "$day"} }}
])

And now the days are strings. As I noted before, if the ordering is important to you then the best approach is to project into a document type as has been done and sort on the numeric keys. Naturally the $project that transforms the date can be wound into the $group stage for brevity, which is probably what you want to do when working with the whole document.




回答2:


This link might give you a hint:

http://docs.mongodb.org/manual/reference/operator/aggregation/concat/

year: {$concat: [ $year ]}



来源:https://stackoverflow.com/questions/21693349/analog-for-group-concat-in-sql

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