按日期转换MongoDB集合

时间:2014-04-17 00:04:28

标签: mongodb mapreduce aggregation-framework

我有一个包含日期的架构的集合。我想对查询的结果进行整形,以便按年份和月份进行分组,但不进行汇总,只进行排序。

所以我的模型看起来像这样:

var RoundSchema = new Schema({
    user: {type: Schema.Types.ObjectId, ref: 'User', required: '{PATH} is required!'},
    course: {type: Schema.Types.ObjectId, ref: 'Course', required: '{PATH} is required!'},
    date: {type: Date, required: '{PATH} is required!'},
    score: Number
});

变形如下:

[
    {
        "year": 2014,
        "month": "April",
        "rounds": [
            {
                "user": "5334d6650685f68c22aa460b",
                "date": "2014-04-23T05:00:00.000Z",
                "course": "5340ab6000806e2433864cfc",
                "score": 73,
                "_id": "534f102667d635381834367b"
            },
            {
                "user": "5334d6650685f68c22aa460b",
                "date": "2014-04-21T05:00:00.000Z",
                "course": "5340ab6000806e2433864cfc",
                "score": 75,
                "_id": "534f100067d6353818343671"
            }
        ]
    },
    {
        "year": 2014,
        "month": "May",
        "rounds": [
            {
                "user": "5334d6650685f68c22aa460b",
                "date": "2014-05-05T05:00:00.000Z",
                "course": "5337611d8d03819024515cf9",
                "score": 81,
                "_id": "534dc38780f1a854236203f3"
            },
            {
                "user": "5334d6650685f68c22aa460b",
                "date": "2014-05-04T05:00:00.000Z",
                "course": "5337611d8d03819024515cf9",
                "score": 77,
                "_id": "534dc22c80f1a854236203e9"
            }
        ]
    }
]

我猜我可以在MongoDB中使用map-reduce或聚合管道,但我无法理解语法。现在感觉像保龄球一样锋利。

任何人都有想法让我开始?

1 个答案:

答案 0 :(得分:1)

这可以使用聚合框架非常简单地完成。这不仅仅是为了总结"价值观,但也擅长文件重塑。

这是你最好的选择,好像"非聚合"使用mapReduce代码看起来有点简单,因为该进程依赖于JavaScript解释器,而不是聚合框架的本机代码,因此mapReduce运行速度会慢得多。大数据相当可观。

db.collection.aggregate([

    // Place all items in an array by year and month
    { "$group": {
        "_id": {
            "year": { "$year": "$date" },
            "month": { "$month": "$date" },
        },
        "rounds": { "$push": {
           "user": "$user",
           "date": "$date",
           "course": "$course",
           "score": "$score",
           "_id": "$_id"
        }}
    }},

    // Sort the results by year and month
    { "$sort": { "_id.year": 1, "_id.date": 1 } }, 

    // Optional project to your exact form
    { "$project": {
        "_id": 0,
        "year": "$_id.year",
        "month": "$_id.month",
        "rounds": 1
    }}

])

或者可能没有您指定的数组,并将所有内容保留为平面形式:

db.collection.aggregate([
    { "$project": {
        "year": { "$year": "$date" },
        "month": { "$month": "$date" },
        "user": 1,
        "date": 1,
        "course": 1,
        "score": 1
    }},
    { "$sort": { "year": 1, "month": 1 } }
])

甚至可以确切地指定您使用月份名称的方式:

db.collection.aggregate([

    // Place all items in an array by year and month
    { "$group": {
        "_id": {
            "year": { "$year": "$date" },
            "month": { "$month": "$date" },
        },
        "rounds": { "$push": {
           "user": "$user",
           "date": "$date",
           "course": "$course",
           "score": "$score",
           "_id": "$_id"
        }}
    }},

    // Sort the results by year and month
    { "$sort": { "_id.year": 1, "_id.date": 1 } }, 

    // Optionally project to your exact form
    { "$project": {
      "_id": 0,
      "year": "$_id.year",
      "month": { "$cond": [
        { "$eq": [ "$_id.month": 1 ] },                 
        "January",
        { "$cond": [
          { "$eq": [ "$_id.month": 2 ] },
          "February",
          { "$cond": [
            { "$eq": [ "$_id.month": 3 ] },
            "March",
            { "$cond": [
              { "$eq": [ "$_id.month": 4 ] },
              "April",
              { "$cond": [
                { "$eq": [ "$_id.month": 5 ] },
                "May",
                { "$cond": [
                  { "$eq": [ "$_id.month": 6 ] },
                  "June",
                  { "$cond": [
                    { "$eq": [ "$_id.month": 7 ] },
                    "July",
                    { "$cond": [
                      { "$eq": [ "$_id.month": 8 ] },
                      "August",
                      { "$cond": [
                        { "$eq": [ "$_id.month": 9 ] },
                        "September",
                        { "$cond": [
                          { "$eq": [ "$_id.month": 10 ] },
                          "October",
                          { "$cond": [
                            { "$eq": [ "$_id.month": 11 ] },
                            "November",
                            "December"
                          ]}
                        ]}
                      ]} 
                    ]}
                  ]} 
                ]}
              ]}
            ]}
          ]}                 
        ]}
      ]},
      "rounds": 1
    }}

])

当然,这是过度的,只是为了表明它可以完成。

当然有Operator reference所以你可以理解所用运算符的用法。您可能希望通过添加自己的 $match 条件来更改此限制,以限制您正在查看的日期范围。或者实际上用于其他目的。