我们有一个事件源系统,出于性能原因,我们将数据缓存到聚合中。
假设我们有三个实体。病人,医生,预约。
对我们来说最有效的是一对多的关系。例如,设想以下事件:
* DOCTOR_CREATED
* DOCTOR_ARRIVED
* DOCTOR_LEFT我们可以聚合成一对多的类型关系。当医生被添加到系统中时,我们可以在数据库中创建一行。
每次他们来上班的时候,我们都可以把这些时间加到医生的记录里,而每次他们离开的时候,我们也可以加进去。这样我们就可以得到这样的结果:
{
"id": 23,
"name": "Dr Bill",
"totalHoursWorked": 124,
"timesheet": [
{
"arrivedAt": "2022-01-04 09:00:00",
"leftAt": "2022-01-04 14:00:00",
"hoursWorked": 5,
},
// etc...
]
}那里没问题。
现在,让我们假设我们想要跟踪约会。这是用户和医生之间的一种多对多的关系.
我对这些活动很感兴趣:
* DOCTOR_CREATED
* PATIENT_CREATED
* APPOINTMENT_CREATED由于事件流必须是经过时间顺序的,所以在创建相关的医生或病人之前,我不能创建预约记录。
如何从约会的角度创建数据模型的视图。
也许用graphql术语来考虑这个问题可能会有帮助,但我想优化这个查询:
query {
appointment {
day
time
patient {
name
age
}
doctor {
name
specialty
}
}
}我希望能够将这个数据结构作为一个聚合存储在数据库中。因此,可以在一个数据库查询中通过ID获取约会。
在这里,我会遇到时间线方面的问题,因为如果我在数据库中创建行之前等待第一个APPOINTMENT_CREATED事件,那么我就错过了相关的病人和医生事件。
如果我先捕捉到病人和医生的事件,然后我必须存储所有可能的医生和病人的组合,只是在他们中的一个不太可能希望以后有预约的时候。我还面临一个问题,即聚合具有不一致的数据结构。表中的行可能由医生-病人id或约会id索引,这取决于事件流的哪个阶段。
我目前认为唯一能做到这一点的方法是让聚合尝试优化这个查询,等待APPOINTMENT_CREATED事件,然后必须异步查询数据库,以便在那个时候检索病人和医生的记录。
尽管我们已经实现了我们的系统,但是我们所有的聚合都是由纯函数的组合而成的,这些函数只接受以前的聚合状态、事件,并返回新的聚合状态。
到目前为止,我想要的建筑是不可能的吗?我是否需要一个转义舱口来允许我们的聚合水合来执行异步db查询(不热衷于此)?
或者是一种集合错误的技术来解决这个问题,而我实际上需要使用其他的东西(比如缓存)。尽管如此,从事件源中卖给我的好处之一是,我们不必费心使用缓存,因为我们可以预先构建所有的聚合,以便为前端进行读取优化。
发布于 2022-02-13 01:45:07
我可以明确地指出,事件源并不会带来不必费心于缓存的好处,也不会真正地与构建前构建的用于前端优化的聚合有任何关系。读取优化的数据模型是CQRS,这与事件来源完全不同(两者都不需要另一个,尽管它们非常适合)。
CQRS/ES系统中的读取端通常不会是事件源:您与事件源一起执行CQRS的原因是,事件源模型对于查询来说很糟糕,因此您正在实现一个非事件源数据模型(例如关系或NoSQL文档).以便进行有效的查询。
所以,不要觉得你需要在读端使用和写端相同的结构。具有与编写端相同的聚合的事件源尤其不太可能带来好处。
如果您确实在读取端使用事件源聚合,请注意,这些聚合将与写入端的聚合不同。例如,构建约会的非规范化视图的过程可能适合事件源聚合:
APPOINTMENT_CREATED事件(可能包括医生ID和病人ID)记录,该过程开始构造一个非规范化视图轻松查询。
注意,在这个过程中,“去正规化过程”聚合是纯的;副作用发生在事件的预测中。
我会在实践中这样做吗?可能不会。我可能使用关系数据库并让读取器进行连接。我可能只是让指定创建的事件启动异步查询来构建一个非规范化视图。尽管如此,这类事情还是有可能的。
https://stackoverflow.com/questions/71085997
复制相似问题