Skip to content

Use this LLM Friendly Docs as an MCP server for Marten.

The search box in the website knows all the secrets—try it!

For any queries, join our Discord Channel to reach us faster.

JasperFx Logo

JasperFx provides formal support for Marten and other JasperFx libraries. Please check our Support Plans for more details.

Projecting by Event Type

While projections can target a specific stream or streams, it is also possible to project by event type. The following sample demonstrates this with a CandleProjection that extends MultiStreamProjection<Candle, Guid> to build Candle aggregates from events of type Tick, grouping every Tick by its CandleId regardless of which stream the event was captured in.

Introduce a type to hold candle data:

cs
public class Candle
{
    public Guid Id { get; set; }
    public decimal Open { get; set; }
    public decimal High { get; set; }
    public decimal Low { get; set; }
    public decimal Close { get; set; }
}

snippet source | anchor

This data will then be populated and updated from observing ticks:

cs
// Each Tick carries the identity of the candle it contributes to. The
// ticks can be captured in any number of separate event streams.
public record Tick(Guid CandleId, decimal Price);

snippet source | anchor

We then introduce a projection that subscribes to the Tick event:

cs
public partial class CandleProjection: MultiStreamProjection<Candle, Guid>
{
    public CandleProjection()
    {
        // Group every Tick event by its CandleId so that all ticks for the
        // same candle are aggregated together, regardless of which stream
        // each Tick was captured in. The projection only reacts to events
        // of type Tick.
        Identity<Tick>(x => x.CandleId);
    }

    public void Apply(Candle candle, Tick tick)
    {
        if (candle.Open == 0)
        {
            candle.Open = tick.Price;
        }

        candle.High = candle.High == 0 ? tick.Price : Math.Max(candle.High, tick.Price);
        candle.Low = candle.Low == 0 ? tick.Price : Math.Min(candle.Low, tick.Price);
        candle.Close = tick.Price;
    }
}

snippet source | anchor

Lastly, we configure the event store to use the newly introduced projection:

cs
var store = DocumentStore.For(opts =>
{
    opts.Connection("some connection string");

    // Register the projection by event type
    opts.Projections.Add<CandleProjection>(ProjectionLifecycle.Inline);
});

snippet source | anchor

Released under the MIT License.