MongoDB是一个通用的工具,但并不完美。对于一些MongoDB不适用的场合,有时可以使用设计模式来处理。MongoDB是一个NoSQL文档型数据库,在大多数情况下是一个比较理想的选择。即使在它不适用的情况下,您仍然可以依靠下面列出的设计模式来克服它的局限性。本文将针对我在另一篇文章《MongoDB的好坏恶》(MongoDB:TheGood,TheBad,andtheUgly)中提到的一些局限性提供相应的解决方案。1.查询命令分离模式,将职责分离到副本集中的不同节点。最基本类型的节点也可能同时占据首要地位,它只需要存储写入和更新所需的数据。查询工作由第二类节点执行。这种模式会提高主节点服务器的写入吞吐量,因为在写入一组对象时,需要更新和插入的数据量也会减少。此外,辅助节点也受益于更少的等待时间。更新数据,它本身有一组针对其工作负载优化的内存工作集。2、应用级事务模式MongoDB不支持事务和文件内部锁定。但是,根据应用程序逻辑,应保留队列使用情况。db.queue.insert({_id:123,message:{},locked:false,tlocked:ISODate(),try:0});vartimerange=date.Now()-TIMECONSTANT;vardoc=db.queue.findAndModify({$or:[{locked:false},{locked:true,tlocked:{$lt:timerange}}],{$set:{locked:true,tlocked:date.Now(),$inc:{try:1}}});//dosomeprocessingdb.queue.update({_id:123,try:doc.try},{});3.Bucketing模式当文本中包含一个不断增长的数组时,使用Bucketing模式,例如指令。并且指令行可能会超出文档大小的合理值。此模式以编程方式处理并由公差计算触发。varTOLERANCE=100;for(recipientinmsg.to){db.inbox.update({owner:msg.to[recipient],count:{$lt:TOLERANCE},time:{$lt:Date.now()}},{$setOnInsert:{owner:msg.to[recipient],time:Date.now()},{$push:{"messages":msg},$inc:{count:1}},{upsert:true});4。关系模式有时候,会出现无法插入整个文档的情况,比如人体建模时,我们可以使用这种模式来建立关系。判断数据是否属于文档,即两者之间是否存在关系。如果可能,插入文档,尤其是面对有用的唯一(专有)数据时。尽量不要引用id值。对关系的有用部分进行非规范化。好的候选人不会经常或从不改变价值观,而且是有用的。专注于非规范化数据更新和关系修复。{_id:1,name:'SamSmith',bio:'SamSmitisaniceguy',best_friend:{id:2,name:'MaryReynolds'},hobbies:[{id:100,n:'Computers'},{id:101,n:'Music'}]}{_id:2,name:'MaryReynolds'bio:'MaryhascomposeddocumentsinMongoDB',best_friend:{id:1,name:'SamSmith'},hobbies:[{id:101,n:'音乐'}]}5.物化路径模式在数据模型的树模式中,相同对象类型是对象的子对象。在这种情况下,可以使用物化路径模型来获得更高效的检索和查询。示例如下:{_id:"Books",path:null}{_id:"Programming",path:",Books,"}{_id:"Databases",path:",Books,Programming,"}{_id:"Languages",path:",Books,Programming,"}{_id:"MongoDB",path:",Books,Programming,Databases,"}{_id:"dbm",path:",Books,Programming,Databases,"}按字段路径查询树模式:db.collection.find().sort({path:1})使用路径字段的正则表达式查找编程的后代集:db.collection.find({path:/,Programming,/})当Books是顶级父级时查询Books的后代集:db.collection.find({path:/^,Books,/})
