Ok, here is source code for my two projections.
The goal is to compute time interval between event “Rest.Api.Events.RestHttpRequestBeganEvent” and event “Rest.Api.Events.RestHttpRequestFinishedEvent”. Each event has correlationId field (GUID) - so we want to compute interval between events which share the same value of correlationId.
First projection “waits” for events to appear in main-stream and links them to temporary streams.
Because CorrelationId is unique for each pair of Rest.Api.Events.RestHttpRequestBeganEvent and Rest.Api.Events.RestHttpRequestFinishedEvent - each temporary stream HttpRestRequest-GUID will contain only two events.
fromStream('main-stream').
when({
"Rest.Api.Events.RestHttpRequestBeganEvent" : function(s,e) {
var correlationId = e.body.CorrelationId;
var streamName = "HttpRestRequest-"+correlationId;
linkTo(streamName,e);
},
"Rest.Api.Events.RestHttpRequestFinishedEvent" : function(s,e) {
var correlationId = e.body.CorrelationId;
var streamName = "HttpRestRequest-"+correlationId;
linkTo(streamName,e);
},
});
Second projection computes time interval between events (event dispatch time is stored in PushTime property in event metadata). Computed interval is stored as new event in http-rest-request-interval-stream.
fromCategory("HttpRestRequest")
.foreachStream()
.when({
$init: function(state, event) { return { "startEvent": null } },
"Rest.Api.Events.RestHttpRequestBeganEvent": function(state, event){
state.startEvent=event;
},
"Rest.Api.Events.RestHttpRequestFinishedEvent": function(state, event){
t1 = Date.parse(JSON.parse(state.startEvent.metadataRaw).PushTime);
t2 = Date.parse(JSON.parse(event.metadataRaw).PushTime);
emit("http-rest-request-interval-stream","HttpRestRequestIntervalComputedEvent", {
"$type": "HttpRestRequestIntervalComputedEvent",
startEvent: {
data: state.startEvent.data,
metadata: JSON.parse(state.startEvent.metadataRaw)
},
endEvent: {
data: event.data,
metadata: JSON.parse(event.metadataRaw)
},
intervalMs: t2-t1
},
{
"SourceName" : "EventStoreProjection",
"AppName" : "EventStore",
"AppVersion" : "20.6",
"PushTime" : new Date().toISOString()
});
},
});
These projections work ok. The only problem is how to delete temporary streams HttpRestRequest-* created ad hoc by first projection after second projection has computed interval.
PS. CorrelationId and PushTime are our custom fields created by our application.