Hi,

I want to solve a real problem I have at a client as POC, by using the eventstore projections. Initially the problem was solved by scheduled SP’s, and now a solutions with a bunch of NServiceBus Handlers is used. But I have the impression that it could be solved simpler with the EventStore projections after the course on Oredev.

Problem:

At a client we have energy meters which register many measurement values. Actually we have a value every 15 minutes. This value is used to display graph’s with averages. The averages are updated and stored when an event is received.

We have following averages:

- Average per hour
- Average per day
- Average per month
- Average per year
- Average per HourOfDay
- Average per DayOfWeek

Theoretical solution with ES Projections:

Let assume we have a stream with measurements of following format:

MeasurmentRead

{

DateTime: timestamp

decimal: value

}

- And we have a stream per Meter:

Eg: MeterTV

- The first projection I would apply is to filter the MeasurementRead event to a separated stream. This would create a sub-set that is used as source for the following projections.

Eg: MeasurementRead

- Then I would apply a projection (linkTo) for each type of average to group the measurements per meter for the time frame of the average:

Eg per hour: MeasurementPeriod-MeterTV+H20121108-12

Eg per day: MeasurementPeriod-MeterTV+D20121108

Eg per month: MeasurementPeriod-MeterTV+M201211

Eg per year: MeasurementPeriod-MeterTV+Y2012

Eg per hour of day: MeasurementPeriod-MeterTV+HD01

Eg per day of week: MeasurementPeriod-MeterTV+Monday

It would be nice assign a catorgy to these streams, so that next projection is only applied to streams with that category. The category in this case is ‘MeasurementPeriod’

- Then I would create a projection to create the total and average per stream creation in previous step. The format would look like this:

MeasurmentAverage

{

decimal: total

decimal: average

int: count

}

Eg per hour: MeasurementAverage-MeterTV+H20121108-12

Eg per day: MeasurementAverage-MeterTV+D20121108

Eg per month: MeasurementAverage-MeterTV+M201211

Eg per year: MeasurementAverage-MeterTV+Y2012

Eg per hour of day: MeasurementAverage-MeterTV+HD01

Eg per day of week: MeasurementAverage-MeterTV+Monday

Question:

I’m aware that this create a hugh amount of streams. Are the ES Projections intended to solve this kind of problems?

My Current Implemention:

- Project all MeasurmentRead’s into a single stream

fromAll().when( {

‘MeasurmentRead’: function (s, e) {

if (e.body == null) return s;

linkTo(‘MeasurmentRead’, e);

return s;

}});

No problems with this one…

- Next projection projects the event per Hour Of Day

fromStream(‘MeasurmentRead’)

.whenAny( function(s,e) {

var FormatName = function(when) {

var date = new Date(when);

return date.getHours();

};

if (e.body == null) return s;

var name = ‘MeasurmentPeriod-’ + e.streamId + ‘+H’ + FormatName(e.body.timestamp);

linkTo(name, e);

return s;

});

This also works, the events are grouped per stream and hour of day.

- Calculate totals per time period

So for this one I assume that all stream + eventd created by previous projection are added to ‘MeasurementPeriod’ category.

So I can calculate the total for each MeasurmentPeriod stream

fromCategory(‘MeasurmentPeriod’)

.fromEachStream()

.whenAny( function (s, e) {

```
if (e.body == null) return s;
var total, count;
var reading = e.body.value;
if (s.data == null)
{
total = reading;
count = 1;
}
else
{
var previous = s.data;
total = previous.total + reading;
count = previous.count + 1;
}
s.data = {
total : e,
count : count,
average: total / count
};
return s;
```

});

This is where I’m stuck for the moment. The projection does not process the event’s from the previous projection. Only the ‘$stream-created’ event of the projected ‘MeasurmentPeriod’ streams is processed. So actually I would like to process the results of a previous projection (by using category). Is there a wathis a scenario that is be supported? Is there an other way to accomplish this?

Thanks in advance,

Tim