Modelling with relationships in eventstore

Hello,

I’m currently having difficulty getting my head around how to model relationships in event store.

I have two entities in my domain EntityA and EntityB. Within my domain model is an event “Linked”, which can be raised against an instance of EntityA. A JSON representation of this event may look like this:

{

“LinkedEntityBId” : “123456”

}

Essentially I am modelling a one-to-many relationship, whereby one instance of EntityA can be linked to multiple instances of EntityB.

When it comes to querying, I am interested in the following question:

  • What instances of EntityA are linked to the instance of EntityB with ID “123456”?
    I am aware that I could achieve this using a projection:

fromCategory(‘EntityA’)

.foreachStream()

.when(

{

Linked : function(s,e) { linkTo(‘EntityBLink-’ + e.data.LinkedEntityBId, e); }

}

)

I can then extract information from the stream “EntityBLink-123456” to help answer my question.

This could be exactly what I have to do, but I am bothered because:

  • There may be millions of instances of EntityA and EntityB in my domain, and hence millions on streams in each corresponding category.
  • Every instance of EntityA is linked to a handful of EntityBs, so my projection will create millions of extra streams - each with maybe a handful of events in them.
  • There may be other “relational queries” I want to run - if I follow this pattern I will end up creating millions more streams!
    I understand that this may not technically be a problem - as eventstore is designed to handle “millions” of streams - but it seems wrong that my stream count increases linearly with the number queries where I wish to query a relationship.

Should I be bothered?!

Lawrence

This would sound like a great place to be querying a read model like
say a relational one?

OK, great - so this is precisely the route I’ve been going down - the data is relational right - why wouldn’t I put it in a relational datastore?

But I care about consistency between querying my relationships, and the events that are in my eventstore.

Perhaps I am under the illusion that if I adopt the projections approach I get some consistency between

a) Reading events of the stream for the instance of EntityA

b) Reading events of the emitted stream EntityBLink-123456

Am I guaranteed this consistency? If not then I need to do some more thinking…

Lawrence

Maybe you can define what you mean by consistency here since it
doesn't match any definition I am aware of.

@Lawerence - you are talking about building the relational database from your events, right?
If so, you only need to know the event checkpoint of the db model.

Apologies for the lax terminology. Let me try to explain a bit better.

To summarise:

  • I wish to model a one-to-many relationship: EntityA ->* EntityB.

  • I raise “Linked” events in my eventstore against instances of EntityA to represent an association:
    {

    “LinkedEntityBId” : “123456”

    }

  • I want to ask questions like:

  • What instances of EntityA are linked to the instance of EntityB with ID “123456”?

  • Is the instance of EntityA with ID “ABCDEFG” linked to the instance of EntityB with ID “123456”?
    I can see two ways of doing achieving this:

Solution 1: Subscribe to the stream of events, and when a “Linked” event is detected I can build up this relationship in a SQL table.

My initial problem with this approach was that now there are two ways of determining if an instance of EntityA is linked to the instance of EntityB with ID 123456:

  1. I can read the stream of events associated to EntityA, and see if 123456 is references in any Linked events;
  2. I can perform a look up in my SQL table.
    I have no guarantees that I will get the same answer with these two approaches (for example - my “subscription process” may have crashed so my SQL table may be a bit behind).

Solution 2: Create a projection, that creates a stream of “Linked” events for each instance of EntityB.

The projection could look something like this:

fromCategory(‘EntityA’)

.foreachStream()

.when(

{

Linked : function(s,e) { linkTo(‘EntityBLink-’ + e.data.LinkedEntityBId, e); }

}

)

As I’ve mentioned in a previous post - this seems like the wrong thing to do - creating multiple streams with few event in them purely for querying a relationship. However - this is certainly an option. As before I now have two options to determine if an instance of EntityA is linked to the instance of EntityB with ID 123456:

  1. I can read the stream of events associated to EntityA, and see if 123456 is references in any Linked events;
  2. I can read the events on the stream EntityBLink-123456 to see if an event linking the instance of EntityB to my EntityA instance appears.
    Where as for “Solution 1” it is very obvious to me that I could get two different answers for the two different ways of answering the question - this is not so obvious to me in the second case. This is what I meant by “consistency” in my previous post - am I guaranteed to get the same answer whether I use either of the two methods above?

However - as I think more about this problem my desire for “consistency” across the two ways of querying may be misplaced. That said - I am still interested in the answer!

Lawrence

"I have no guarantees that I will get the same answer with these two
approaches (for example - my "subscription process" may have crashed
so my SQL table may be a bit behind). "

Internal projections run asynchronously as well.

Thanks - that makes things clearer for me.