设为首页 收藏本站
查看: 1939|回复: 0

[经验分享] MongoDB学习之树结构例子(使用NORM驱动)

[复制链接]
累计签到:2 天
连续签到:1 天
发表于 2018-10-28 10:36:08 | 显示全部楼层 |阅读模式
  近期NoSql数据库比较火,于是本着与时俱进的态度,开始对MongoDB进行学习。学习的最好方法就是动手做做实例,于是选择了经常使用到的树结构作为入门例子。本例子将根据《Tree in MongoDB》推荐的全路径方法构建树结构。
  首先要做的是如图一所示的操作页面。
DSC0000.gif

  操作页面很简单,就是用Ext的树控件创建一个树结构,通过控件上的小按钮对树进行添加、删除操作。直接单击树节点可的节点文字进行修改。因为本文的重点不是Ext界面,所以操作页面的代码就不多说,有兴趣可以下载源代码进行研究。
  下面主要来学习一下操作MongoDB后台代码。首先是要根据树结构定义一个类,类定义如下:
  


  • public class Node
  • {
  •     public ObjectId ID { get; set; }
  •     public string title {get;set;}
  •     public int depth { get; set; }
  •     public string path { get; set; }
  • }
  

  从类定义中可以看到,树节点的存储结构主要有4个项,ID为唯一编号,title为节点名称,depth是节点的深度, path是节点的全路径。
  下面要完成的是子节点的查询操作,代码如下:
  


  • private string List(HttpContext context)
  •     {
  •         string nodeid = context.Request.Params["node"] ?? "";
  •         JArray ja = new JArray();
  •         using (var mongo = Mongo.Create("mongodb://192.168.0.77/Trees"))
  •         {
  •             var nodes = mongo.GetCollection("Node");
  •             if (nodeid == "" | nodeid == "rootnode")
  •             {
  •                 var q = nodes.Find(new { depth = 0 });
  •                 foreach (var c in q)
  •                 {
  •                     ja.Add(new JObject(
  •                         new JProperty("id", c.ID.ToString()),
  •                         new JProperty("text", c.title),
  •                         new JProperty("leaf", false)
  •                         ));
  •                 }
  •             }
  •             else
  •             {
  •                 Node node = nodes.FindOne(new { _id = new ObjectId(nodeid) });
  •                 if (node != null)
  •                 {
  •                     var q = nodes.Find(new { path = new Regex("^" + node.path), depth = node.depth + 1 });
  •                     foreach (var c in q)
  •                     {
  •                         ja.Add(new JObject(
  •                             new JProperty("id", c.ID.ToString()),
  •                             new JProperty("text", c.title),
  •                             new JProperty("leaf", false)
  •                             ));
  •                     }
  •                 }
  •             }
  •         }
  •         return ja.ToString();
  •     }
  

  List方法的代码中,第一行是获取父节点id。JArry对象ja的作用是返回子节点数组。要注意以下这句:
  


  • using (var mongo = Mongo.Create("mongodb://192.168.0.77/Trees"))
  

  这里建议使用using关键字,主要原因是让对象自动释放连接,不然当操作频繁的时候,因为连接没有释放,会产生“norm.mongo exception: connection timeout trying to get connection from connection pool”的错误。在调试时,很是困扰了笔者一段时间。
  在有些文章会使用new MongoDB连接数据库,具体有什么不同,笔者没仔细研究。使用Create方法是根据NORM的测试例子依样画葫芦而已。这个可根据个人习惯选择。如果MongoDB的端口不同,可在IP地址后加上端口号,譬如端口号为10000,可修改代码如下:
  


  • using (var mongo = Mongo.Create("mongodb://192.168.0.77:10000/Trees"))
  

  连接字符串中的“Trees”为要连接的数据库名称。
  下面一句就是从数据库中获取数据集合。如果需要返回根节点的子节点,则直接搜索depth为0的节点就行。否则需要先通过FindOne方法获取父节点,然后使用父节点的路径(path)通过正则表达式查询其子节点。在这里因为要返回的只是父节点的下一级子节点,所以需要增加一个节点深度条件(depth = node.depth + 1)。
  下面是Add方法的代码,用来增加树节点:
  


  • private string Add(HttpContext context)
  •     {
  •         string output = "";
  •         string title = context.Request.Params["value"] ?? "";
  •         if (title.Length > 0)
  •         {
  •             string nodeid = context.Request.Params["parentid"] ?? "";
  •             using (var mongo = Mongo.Create("mongodb://192.168.0.77/Trees"))
  •             {
  •                 var nodes = mongo.GetCollection("Node");
  •                 var node = new Node();
  •                 node.ID = ObjectId.NewObjectId();
  •                 node.title = title;
  •                 node.depth = 0;
  •                 node.path = node.ID + ",";
  •                 if (nodeid.Length > 0)
  •                 {
  •                     Node q = nodes.FindOne(new { _id = new ObjectId(nodeid) });
  •                     if (q != null)
  •                     {
  •                         node.depth = q.depth + 1;
  •                         node.path = q.path + node.ID + ",";
  •                     }
  •                 }
  •                 nodes.Insert(node);
  •                 output = (new JObject
  •                     {
  •                         new JProperty("success",true),
  •                         new JProperty("data",new JObject(
  •                                 new JProperty("id",node.ID.ToString()),
  •                                 new JProperty("text",node.title),
  •                                 new JProperty("leaf",false)
  •                             ))
  •                     }).ToString();
  •             }
  •         }
  •         else
  •         {
  •             output = (new JObject
  •             {
  •                 new JProperty("success",false),
  •                 new JProperty("data","请输入节点名称")
  •             }).ToString();
  •         }
  •         return output;
  •     }
  

  添加子节点比较简单,只要创建一个Node对象,然后使用Inser方法保存就行了。新创建的Node对象默认是顶层节点,如果父节点存在,则修改Node对象的depth属性和path属性即可。
  下面是Del方法的代码,用于删除节点:
  


  • private string Del(HttpContext context)
  •     {
  •         string output="";
  •         string id = context.Request.Params["id"] ?? "";
  •         if (id.Length > 0)
  •         {
  •             using (var mongo = Mongo.Create("mongodb://192.168.0.77/Trees"))
  •             {
  •                 var nodes = mongo.GetCollection("Node");
  •                 Node q = nodes.FindOne(new { _id = new ObjectId(id) });
  •                 if (q != null)
  •                 {
  •                     nodes.Delete(new { path = new Regex("^" + q.path) });
  •                     output = (new JObject
  •                         {
  •                             new JProperty("success",true),
  •                             new JProperty("data",id)
  •                         }).ToString();
  •                 }
  •                 else
  •                 {
  •                     output = (new JObject
  •                         {
  •                             new JProperty("success",false),
  •                             new JProperty("data","要删除的节点不存在或已被删除!")
  •                         }).ToString();
  •                 }
  •             }
  •         }
  •         else
  •         {
  •             output = (new JObject
  •             {
  •                 new JProperty("success",false),
  •                 new JProperty("data","请选择要删除的节点!")
  •             }).ToString();
  •         }
  •         return output;
  •     }
  

  因为使用全路径的结构,所以删除一个节点及其子节点变得相当简单,只要通过该节点的全路径,使用正则表达式搜索到节点本身及其子节点就行了。在例子中使用以下语句就轻松完成了删除操作:
  


  • nodes.Delete(new { path = new Regex("^" + q.path) });
  

  下面是Edit方法的代码,用于修改节点的名称:
  


  • private string Edit(HttpContext context)
  •     {
  •         string output = "";
  •         string id = context.Request.Params["id"] ?? "";
  •         string title = context.Request.Params["value"] ?? "";
  •         if (title.Length > 0)
  •         {
  •             if (id.Length > 0)
  •             {
  •                 using (var mongo = Mongo.Create("mongodb://192.168.0.77/Trees"))
  •                 {
  •                     var nodes = mongo.GetCollection("Node");
  •                     Node q = nodes.FindOne(new { _id = new ObjectId(id) });
  •                     if (q != null)
  •                     {
  •                         q.title = title;
  •                         nodes.Save(q);
  •                         output = (new JObject
  •                         {
  •                             new JProperty("success",true),
  •                             new JProperty("data",id)
  •                         }).ToString();
  •                     }
  •                     else
  •                     {
  •                         output = (new JObject
  •                             {
  •                                 new JProperty("success",false),
  •                                 new JProperty("data","要修改的节点不存在或已被删除!")
  •                             }).ToString();
  •                     }
  •                 }
  •             }
  •             else
  •             {
  •                 output = (new JObject
  •                 {
  •                     new JProperty("success",false),
  •                     new JProperty("data","要修改的节点不存在或已被删除!")
  •                 }).ToString();
  •             }
  •         }
  •         else
  •         {
  •             output = (new JObject
  •                 {
  •                     new JProperty("success",false),
  •                     new JProperty("data","请输入节点名称!")
  •                 }).ToString();
  •         }
  •         return output;
  •     }
  

  代码中首先要判断提交过来的节点名称是否为空,如果不为空则继续判断提交的节点id是否正确,接着需要通过 FindOne方法搜索节点,修改title属性后,通过save方法保存即可完成操作。
  例子已经完成了,从例子中可以看到,使用NORM操作MongoDB相当方便,代码很简洁。
  通过例子可以看到,使用全路径的方法,在MongoDB中创建一个无级树是相当的方便,因为路径不受数据库字段长度的限制,不过如果考虑MongoDB的存储大小的话,估计也是一个问题,不过这个有待测试。这也是NoSql数据库的一个优势吧。
  

  源代码下载地址:http://download.csdn.net/source/2652662



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-627410-1-1.html 上篇帖子: 推荐:MongoDB学习资料 下篇帖子: 基于MongoDB MapReduce的统计分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表