복붙노트

[MONGODB] 매일 그룹 내에서 MongoDB를 집계 [중복]

MONGODB

매일 그룹 내에서 MongoDB를 집계 [중복]

내가 이렇게 보이는 몽고에서 일부 문서를 가지고 :

{
  _id : ObjectId("..."),
  "make" : "Nissan",
  ..
},
{
  _id : ObjectId("..."),
  "make" : "Nissan",
  "saleDate" :  ISODate("2013-04-10T12:39:50.676Z"),
  ..
}

이상적으로, 내가 셀 수 있도록하고 싶습니다, 메이크업에 의해, 차량의 수는 하루에 판매했다. 그때처럼은 지난 7 일을 통해 같은 오늘로 하나 오늘, 또는 창을 볼 것입니다.

나는 못생긴 코드로 매일보기를 달성 할 수 있었다

db.inventory.aggregate(
  { $match : { "saleDate" : { $gte: ISODate("2013-04-10T00:00:00.000Z"), $lt: ISODate("2013-04-11T00:00:00.000Z")  } } } ,
  { $group : { _id : { make : "$make", saleDayOfMonth : { $dayOfMonth : "$saleDate" } }, cnt : { $sum : 1 } } }
)

어느 다음 결과를 얻을 수

{
  "result" : [
    {
      "_id" : {
        "make" : "Nissan",
        "saleDayOfMonth" : 10
      },
      "cnt" : 2
    },
    {
      "_id" : {
        "make" : "Toyota",
        "saleDayOfMonth" : 10
      },
      "cnt" : 4
    },
  ],
  "ok" : 1
}

그 괜찮 그래서,하지만 난 많은 쿼리에서 두 날짜 값을 변경할 필요가 없습니다 선호하는 것입니다. 제가 위에서 언급 한 바와 같이 다음, 나는 마지막 주에 하루 비닝 같은 결과를 볼 (그 때마다 수정할 필요없이, 다시)이 쿼리를 실행할 수 있도록하고 싶습니다.

아, 그리고 여기에 내가 쿼리를 위해 사용했던 샘플 데이터입니다

db.inventory.save({"make" : "Nissan","saleDate" :  ISODate("2013-04-10T12:39:50.676Z")});
db.inventory.save({"make" : "Nissan"});
db.inventory.save({"make" : "Nissan","saleDate" :  ISODate("2013-04-10T11:39:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" :  ISODate("2013-04-09T11:39:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" :  ISODate("2013-04-10T11:38:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" :  ISODate("2013-04-10T11:37:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" :  ISODate("2013-04-10T11:36:50.676Z")});
db.inventory.save({"make" : "Toyota","saleDate" :  ISODate("2013-04-10T11:35:50.676Z")});

미리 감사드립니다, 케빈

해결법

  1. ==============================

    1.$ dateToString 하루가 그룹에 사용하고 단순히 결과에 "YYYY-MM-DD"가 될 수있다 : 몽고 2.8 RC2에서 새 데이터 집합 연산자가있다 :

    $ dateToString 하루가 그룹에 사용하고 단순히 결과에 "YYYY-MM-DD"가 될 수있다 : 몽고 2.8 RC2에서 새 데이터 집합 연산자가있다 :

    문서에서 예제 :

    db.sales.aggregate(
      [
         {
             $project: {
                    yearMonthDay: { $dateToString: { format: "%Y-%m-%d", date: "$date" } },
                    time: { $dateToString: { format: "%H:%M:%S:%L", date: "$date" } }
             }
         }
      ]
    )
    

    에서 발생합니다 :

    { "_id" : 1, "yearMonthDay" : "2014-01-01", "time" : "08:15:39:736" }
    
  2. ==============================

    2.날짜를 기반으로 UPDATE 업데이트 된 대답은 3.6뿐만 아니라 (광산을 포함한 모든 원래의 답변에 언급되지 않은) 판매가 없었다 범위의 날짜를 포함하는 방법을 보여주는에 있습니다.

    날짜를 기반으로 UPDATE 업데이트 된 대답은 3.6뿐만 아니라 (광산을 포함한 모든 원래의 답변에 언급되지 않은) 판매가 없었다 범위의 날짜를 포함하는 방법을 보여주는에 있습니다.

    샘플 데이터 :

    db.inventory.find()
    { "_id" : ObjectId("5aca30eefa1585de22d7095f"), "make" : "Nissan", "saleDate" : ISODate("2013-04-10T12:39:50.676Z") }
    { "_id" : ObjectId("5aca30eefa1585de22d70960"), "make" : "Nissan" }
    { "_id" : ObjectId("5aca30effa1585de22d70961"), "make" : "Nissan", "saleDate" : ISODate("2013-04-10T11:39:50.676Z") }
    { "_id" : ObjectId("5aca30effa1585de22d70962"), "make" : "Toyota", "saleDate" : ISODate("2013-04-09T11:39:50.676Z") }
    { "_id" : ObjectId("5aca30effa1585de22d70963"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:38:50.676Z") }
    { "_id" : ObjectId("5aca30effa1585de22d70964"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:37:50.676Z") }
    { "_id" : ObjectId("5aca30effa1585de22d70965"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:36:50.676Z") }
    { "_id" : ObjectId("5aca30effa1585de22d70966"), "make" : "Toyota", "saleDate" : ISODate("2013-04-10T11:35:50.676Z") }
    { "_id" : ObjectId("5aca30f9fa1585de22d70967"), "make" : "Toyota", "saleDate" : ISODate("2013-04-11T11:35:50.676Z") }
    { "_id" : ObjectId("5aca30fffa1585de22d70968"), "make" : "Toyota", "saleDate" : ISODate("2013-04-13T11:35:50.676Z") }
    { "_id" : ObjectId("5aca3921fa1585de22d70969"), "make" : "Honda", "saleDate" : ISODate("2013-04-13T00:00:00Z") }
    

    변수로의 startDate와 endDate가 정의 및 집계에서 그들을 사용 :

    startDate = ISODate("2013-04-08T00:00:00Z");
    endDate = ISODate("2013-04-15T00:00:00Z");
    
    db.inventory.aggregate([
      { $match : { "saleDate" : { $gte: startDate, $lt: endDate} } },
      {$addFields:{
         saleDate:{$dateFromParts:{
                      year:{$year:"$saleDate"},
                      month:{$month:"$saleDate"},
                      day:{$dayOfMonth:"$saleDate"}
         }},
         dateRange:{$map:{
            input:{$range:[0, {$subtract:[endDate,startDate]}, 1000*60*60*24]},
            in:{$add:[startDate, "$$this"]}
         }}
      }},
      {$unwind:"$dateRange"},
      {$group:{
         _id:"$dateRange", 
         sales:{$push:{$cond:[
                    {$eq:["$dateRange","$saleDate"]},
                    {make:"$make",count:1},
                    {count:0}
         ]}}
      }},
      {$sort:{_id:1}},
      {$project:{
         _id:0,
         saleDate:"$_id",
         totalSold:{$sum:"$sales.count"},
         byBrand:{$arrayToObject:{$reduce:{
            input: {$filter:{input:"$sales",cond:"$$this.count"}},
            initialValue: {$map:{input:{$setUnion:["$sales.make"]}, in:{k:"$$this",v:0}}}, 
            in:{$let:{
               vars:{t:"$$this",v:"$$value"},
               in:{$map:{
                  input:"$$v",
                  in:{
                     k:"$$this.k",
                     v:{$cond:[
                         {$eq:["$$this.k","$$t.make"]},
                         {$add:["$$this.v","$$t.count"]},
                         "$$this.v"
                     ]}
                  }
               }}
            }}
         }}}
      }}
    ])
    

    샘플 데이터에이 결과를 제공합니다 :

    { "saleDate" : ISODate("2013-04-08T00:00:00Z"), "totalSold" : 0, "byBrand" : {  } }
    { "saleDate" : ISODate("2013-04-09T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1 } }
    { "saleDate" : ISODate("2013-04-10T00:00:00Z"), "totalSold" : 6, "byBrand" : { "Nissan" : 2, "Toyota" : 4 } }
    { "saleDate" : ISODate("2013-04-11T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1 } }
    { "saleDate" : ISODate("2013-04-12T00:00:00Z"), "totalSold" : 0, "byBrand" : {  } }
    { "saleDate" : ISODate("2013-04-13T00:00:00Z"), "totalSold" : 2, "byBrand" : { "Honda" : 1, "Toyota" : 1 } }
    { "saleDate" : ISODate("2013-04-14T00:00:00Z"), "totalSold" : 0, "byBrand" : {  } }
    

    이 집계는 또한 2 개 $ 그룹 스테이지 간단한 $ 프로젝트 대신 $ 그룹과 복잡한 $ 프로젝트를 수행 할 수 있습니다. 여기있어:

    db.inventory.aggregate([
       {$match : { "saleDate" : { $gte: startDate, $lt: endDate} } },
       {$addFields:{saleDate:{$dateFromParts:{year:{$year:"$saleDate"}, month:{$month:"$saleDate"}, day:{$dayOfMonth : "$saleDate" }}},dateRange:{$map:{input:{$range:[0, {$subtract:[endDate,startDate]}, 1000*60*60*24]},in:{$add:[startDate, "$$this"]}}}}},
       {$unwind:"$dateRange"},
       {$group:{
          _id:{date:"$dateRange",make:"$make"},
          count:{$sum:{$cond:[{$eq:["$dateRange","$saleDate"]},1,0]}}
       }},
       {$group:{
          _id:"$_id.date",
          total:{$sum:"$count"},
          byBrand:{$push:{k:"$_id.make",v:{$sum:"$count"}}}
       }},
       {$sort:{_id:1}},
       {$project:{
          _id:0,
          saleDate:"$_id",
          totalSold:"$total",
          byBrand:{$arrayToObject:{$filter:{input:"$byBrand",cond:"$$this.v"}}}
       }}
    ])
    

    같은 결과 :

    { "saleDate" : ISODate("2013-04-08T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Honda" : 0, "Toyota" : 0, "Nissan" : 0 } }
    { "saleDate" : ISODate("2013-04-09T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Honda" : 0, "Nissan" : 0, "Toyota" : 1 } }
    { "saleDate" : ISODate("2013-04-10T00:00:00Z"), "totalSold" : 6, "byBrand" : { "Honda" : 0, "Toyota" : 4, "Nissan" : 2 } }
    { "saleDate" : ISODate("2013-04-11T00:00:00Z"), "totalSold" : 1, "byBrand" : { "Toyota" : 1, "Honda" : 0, "Nissan" : 0 } }
    { "saleDate" : ISODate("2013-04-12T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Toyota" : 0, "Nissan" : 0, "Honda" : 0 } }
    { "saleDate" : ISODate("2013-04-13T00:00:00Z"), "totalSold" : 2, "byBrand" : { "Honda" : 1, "Toyota" : 1, "Nissan" : 0 } }
    { "saleDate" : ISODate("2013-04-14T00:00:00Z"), "totalSold" : 0, "byBrand" : { "Toyota" : 0, "Honda" : 0, "Nissan" : 0 } }
    

    2.6에 따라 원래 답변 :

    현재 집계 프레임 워크의 다양한 날짜 조작을 처리하는 방법에 대한 내 블로그 항목을 살펴 할 수 있습니다.

    당신이 할 수있는 것은 매일 해상도로 날짜를 절단 한 후 날짜와 메이크업에 의해 전체 데이터 집합 (또는 그것의 한 부분) 및 집계를 통해 집계를 실행하는 데 사용할 $ 프로젝트 단계입니다.

    샘플 데이터와 함께, 당신은 당신이 날짜 올해, 메이크업에 의해 판매 얼마나 많은 차량을 알고 싶은 말 :

    match={"$match" : {
                   "saleDate" : { "$gt" : new Date(2013,0,1) }
          }
    };
    
    proj1={"$project" : {
            "_id" : 0,
            "saleDate" : 1,
            "make" : 1,
            "h" : {
                "$hour" : "$saleDate"
            },
            "m" : {
                "$minute" : "$saleDate"
            },
            "s" : {
                "$second" : "$saleDate"
            },
            "ml" : {
                "$millisecond" : "$saleDate"
            }
        }
    };
    
    proj2={"$project" : {
            "_id" : 0,
            "make" : 1,
            "saleDate" : {
                "$subtract" : [
                    "$saleDate",
                    {
                        "$add" : [
                            "$ml",
                            {
                                "$multiply" : [
                                    "$s",
                                    1000
                                ]
                            },
                            {
                                "$multiply" : [
                                    "$m",
                                    60,
                                    1000
                                ]
                            },
                            {
                                "$multiply" : [
                                    "$h",
                                    60,
                                    60,
                                    1000
                                ]
                            }
                        ]
                    }
                ]
            }
        }
    };
    
    group={"$group" : {
            "_id" : {
                "m" : "$make",
                "d" : "$saleDate"
            },
            "count" : {
                "$sum" : 1
            }
        }
    };
    

    이제 집계를 실행하면이 있습니다 :

    db.inventory.aggregate(match, proj1, proj2, group)
    {
        "result" : [
            {
                "_id" : {
                    "m" : "Toyota",
                    "d" : ISODate("2013-04-10T00:00:00Z")
                },
                "count" : 4
            },
            {
                "_id" : {
                    "m" : "Toyota",
                    "d" : ISODate("2013-04-09T00:00:00Z")
                },
                "count" : 1
            },
            {
                "_id" : {
                    "m" : "Nissan",
                    "d" : ISODate("2013-04-10T00:00:00Z")
                },
                "count" : 2
            }
        ],
        "ok" : 1
    }
    

    당신은 꽤 출력까지 또 다른 {$ 프로젝트} 단계를 추가 할 수 있습니다 당신은 {$ 일종의} 단계를 추가 할 수 있지만 기본적으로 각 날짜에 대해, 각각의 메이크업을 위해 당신이 판매되었다 얼마나 많은 수를 얻을.

  3. ==============================

    3.I user1083621의 답변을 좋아하지만 그 방법은이 분야에 작업을 다음 몇 가지 제한 사항이 발생합니다 - 당신은 (예를 들어) 다음 집계 파이프 라인 단계에서 날짜 필드로 사용할 수 있기 때문이다. 당신은 어느 쪽도 비교하거나 임의 날짜 집계 작업을 사용하여 집계 한 후 문자열을해야 할 수 있습니다 (!). 그 모두는 원래 날짜 필드를 투영함으로써 해결 될 수 있지만 그 경우에 당신은 단계를 groupping을 통해 그것을 유지에 어려움을 얻을 것이다. 그리고 결국, 때로는 그냥 임의의 일 시간이 하루의 시작으로 조작 할 수 있습니다. 그래서 여기 내 방법입니다 :

    I user1083621의 답변을 좋아하지만 그 방법은이 분야에 작업을 다음 몇 가지 제한 사항이 발생합니다 - 당신은 (예를 들어) 다음 집계 파이프 라인 단계에서 날짜 필드로 사용할 수 있기 때문이다. 당신은 어느 쪽도 비교하거나 임의 날짜 집계 작업을 사용하여 집계 한 후 문자열을해야 할 수 있습니다 (!). 그 모두는 원래 날짜 필드를 투영함으로써 해결 될 수 있지만 그 경우에 당신은 단계를 groupping을 통해 그것을 유지에 어려움을 얻을 것이다. 그리고 결국, 때로는 그냥 임의의 일 시간이 하루의 시작으로 조작 할 수 있습니다. 그래서 여기 내 방법입니다 :

    {'$project': {
        'start_of_day': {'$subtract': [
            '$date',
            {'$add': [
                {'$multiply': [{'$hour': '$date'}, 3600000]},
                {'$multiply': [{'$minute': '$date'}, 60000]},
                {'$multiply': [{'$second': '$date'}, 1000]},
                {'$millisecond': '$date'}
            ]}
        ]},
    }}
    

    그것은 당신이 제공 :

    {
        "start_of_day" : ISODate("2015-12-03T00:00:00.000Z")
    },
    {
        "start_of_day" : ISODate("2015-12-04T00:00:00.000Z")
    }
    

    빨리 user1083621의 방법보다 그 경우라고 할 수 없습니다.

  4. from https://stackoverflow.com/questions/15938859/mongodb-aggregate-within-daily-grouping by cc-by-sa and MIT license