2013-04-24 13 views
7

Przykładowe dokumenty:MongoDB Aggregation: Compute bieganie Sumy od sumy poprzednich wierszach

{ 
_id: ObjectId('4f442120eb03305789000000'), 
time: ISODate("2013-10-10T20:55:36Z"), 
value:1 
}, 
{ 
_id: ObjectId('4f442120eb03305789000001'), 
time: ISODate("2013-10-10T28:43:16Z"), 
value:2 
}, 
{ 
_id: ObjectId('4f442120eb03305789000002'), 
time: ISODate("2013-10-11T27:12:66Z"), 
value:3 
}, 
{ 
_id: ObjectId('4f442120eb03305789000003'), 
time: ISODate("2013-10-11T10:15:38Z"), 
value:4 
}, 
{ 
_id: ObjectId('4f442120eb03305789000004'), 
time: ISODate("2013-10-12T26:15:38Z"), 
value:5 
} 

Łatwo jest dostać zagregowane wyniki, które są pogrupowane według daty. Ale co chcę jest do kwerendy wyniki Zwraca bieżącą łączną sumowania, jak:

{ 
time: "2013-10-10" 
total: 3, 
runningTotal: 3 
}, 
{ 
time: "2013-10-11" 
total: 7, 
runningTotal: 10 
}, 
{ 
time: "2013-10-12" 
total: 5, 
runningTotal: 15 
} 

Czy to możliwe z MongoDB Aggregation?

+1

Czy można zachować uruchomioną sumie jak iść. Byłoby to najłatwiejsze i najbardziej wydajne, zwłaszcza, że ​​dane się nie zmieniają. Struktura agregacji byłaby dość kosztownym sposobem obliczania tego rodzaju danych statycznych w locie. – cirrus

+1

obecnie nie można tego zrobić za pomocą struktury agregacji. –

+0

@cirrus Dzięki za odpowiedź. Nie jestem do końca pewien, jak to zrobić ... – user2315268

Odpowiedz

2

To robi to, czego potrzebujesz. Znormalizowałem czas w danych, więc grupują się razem (można zrobić coś takiego jak this). Chodzi o to, aby $group i wypchnąć time 's i total' s do oddzielnych tablic. Następnie $unwind tablica time i utworzono kopię tablicy totals dla każdego dokumentu time. Następnie możesz obliczyć wartość runningTotal (lub coś w rodzaju średniej kroczącej) z tablicy zawierającej wszystkie dane dla różnych czasów. "Indeks" wygenerowany przez $unwind jest indeksem tablicy dla total odpowiadającym temu time. Ważne jest, aby $sort przed $unwind ing, ponieważ zapewnia to, że tablice są we właściwej kolejności.

db.temp.aggregate(
    [ 
     { 
      '$group': { 
       '_id': '$time', 
       'total': { '$sum': '$value' } 
      } 
     }, 
     { 
      '$sort': { 
       '_id': 1 
      } 
     }, 
     { 
      '$group': { 
       '_id': 0, 
       'time': { '$push': '$_id' }, 
       'totals': { '$push': '$total' } 
      } 
     }, 
     { 
      '$unwind': { 
       'path' : '$time', 
       'includeArrayIndex' : 'index' 
      } 
     }, 
     { 
      '$project': { 
       '_id': 0, 
       'time': { '$dateToString': { 'format': '%Y-%m-%d', 'date': '$time' } }, 
       'total': { '$arrayElemAt': [ '$totals', '$index' ] }, 
       'runningTotal': { '$sum': { '$slice': [ '$totals', { '$add': [ '$index', 1 ] } ] } }, 
      } 
     }, 
    ] 
); 

Użyłem czegoś podobnego w kolekcji z ~ 80 000 dokumentów, agregując do 63 wyników. Nie mam pewności, jak dobrze będzie działać na większych kolekcjach, ale odkryłem, że wykonywanie przekształceń (rzutowania, manipulacje tablicami) na zagregowanych danych nie wydaje się mieć dużego kosztu wydajności, gdy dane zostaną zredukowane do możliwego do zarządzania rozmiaru.

0

tutaj jest inne podejście

rurociąg

db.col.aggregate([ 
    {$group : { 
     _id : { time :{ $dateToString: {format: "%Y-%m-%d", date: "$time", timezone: "-05:00"}}}, 
     value : {$sum : "$value"} 
    }}, 
    {$addFields : {_id : "$_id.time"}}, 
    {$sort : {_id : 1}}, 
    {$group : {_id : null, data : {$push : "$$ROOT"}}}, 
    {$addFields : {data : { 
     $reduce : { 
      input : "$data", 
      initialValue : {total : 0, d : []}, 
      in : { 
       total : {$sum : ["$$this.value", "$$value.total"]},     
       d : {$concatArrays : [ 
         "$$value.d", 
         [{ 
          _id : "$$this._id", 
          value : "$$this.value", 
          runningTotal : {$sum : ["$$value.total", "$$this.value"]} 
         }] 
       ]} 
      } 
     } 
    }}}, 
    {$unwind : "$data.d"}, 
    {$replaceRoot : {newRoot : "$data.d"}} 
]).pretty() 

kolekcja

> db.col.find() 
{ "_id" : ObjectId("4f442120eb03305789000000"), "time" : ISODate("2013-10-10T20:55:36Z"), "value" : 1 } 
{ "_id" : ObjectId("4f442120eb03305789000001"), "time" : ISODate("2013-10-11T04:43:16Z"), "value" : 2 } 
{ "_id" : ObjectId("4f442120eb03305789000002"), "time" : ISODate("2013-10-12T03:13:06Z"), "value" : 3 } 
{ "_id" : ObjectId("4f442120eb03305789000003"), "time" : ISODate("2013-10-11T10:15:38Z"), "value" : 4 } 
{ "_id" : ObjectId("4f442120eb03305789000004"), "time" : ISODate("2013-10-13T02:15:38Z"), "value" : 5 } 

wynik

{ "_id" : "2013-10-10", "value" : 3, "runningTotal" : 3 } 
{ "_id" : "2013-10-11", "value" : 7, "runningTotal" : 10 } 
{ "_id" : "2013-10-12", "value" : 5, "runningTotal" : 15 } 
>