MongoDB是一个面向Document的NoSQL数据库。如果我们仍然以RDB的方式来思考MongoDB的数据建模,就不能有效地利用MongoDB的优势;但是,我们不能因为Document的Flexibility,在设计之初就放过它。适度的建模是非常必要的,尤其是对于比较复杂的关系。因为在MongoDB中,Link和Embedded都可以用来处理这种关系。我们需要评估一个决定,不能脱离具体的语境来做出判断。简单地说技术A比技术B更好的方式就像一个孩子看卡通人物只知道谁是好人。谁像小人一样天真。世界上没有完美的技术,关键看能否结合场景恰当使用。例如,使用嵌入式方法有其自身的优点和缺点。例如,如果我们使用Embedded方法将地址用作Person对象内的数组:{name:'KateMonster',ssn:'123-456-7890',addresses:[{street:'123SesameSt',city:'Anytown',cc:'USA'},{street:'123AvenueQ',city:'NewYork',cc:'USA'}]}当我们查询Person的信息时,不需要执行多次查询。如果我们改变领域场景,我们需要开发一个任务跟踪系统。如果我们将Tasks信息嵌入到Person对象中,当我们面临如下需求时:显示所有明天到期的任务显示所有未完成的任务使用这种Embedded并不是那么愉快。如果使用Link方式,情况就完全不同了://Tasks[{_id:ObjectID('AAAA'),task_number:1234,taks_name:'PrepareMongoDBenvironment',due_date:'2017-01-15'},{_id:ObjectID('BBBB'),task_number:1235,taks_name:'ImportTestData',due_date:'2017-02-15'},]//Persons{name:'KateMonster',role:'Manager',tasks:[ObjectID('AAAA'),ObjectID('BBBB')]}有得有失。当我们需要查询Person所承担的Tasks时,这种方式需要使用应用层的join方式进行两次查询。这种建模方式也带来了另一种可能性,即原来的Person->Tasks的一对N关系可以变成N对N的关系,因为一个Task可以被多个Person拥有。如果使用Embedded方式,会导致Task数据冗余。在文章6RulesofThumbforMongoDBSchemaDesign中,作者将这种1对N关联实现的判断依据分为三种形式:one-to-fewone-to-manyone-to-squillions但是我觉得如何要实现关联,应该从Entities之间的领域关系来判断。我们可以引入DDDAggregation设计理念作为建模的基础。简单来说,如果使用Embedded,可以认为Entity在Aggregation边界内,外部应该通过AggregationRoot访问。文章6RulesofThumbforMongoDBSchemaDesign说:一对N的“N”侧的实体是否需要独立?如果是StandAlone,表示Entity可以成为一个独立的Aggregation,然后通过ID关联到另一个Aggregate。有人对SegmentFault做了这样的总结:FirstClass(比如“User”)应该使用一个独立的Collection“入口类型”,并且应该嵌入。如果两个模型之间存在包含关系,则使用嵌入式多对多关系,使用链接(类似于sql中的foreginkey)如果一个模型可能存储的对象很少,则使用独立的集合,这有助于mongodb服务器做缓存。嵌入式方法不利于复杂的关联和复杂的查询,嵌入式方法的性能非常有优势。如果有“性能”需求,可以考虑使用embed【本文为专栏作家“张艺”原创稿件,转载请联系原作者】点此查看该作者更多好文
