MongoDB學習之樹結構例子(使用NORM驅動)

來源:互聯網
上載者:User

      近期NoSql資料庫比較火,於是本著與時俱進的態度,開始對MongoDB進行學習。學習的最好方法就是動手做做執行個體,於是選擇了經常使用到的樹結構作為入門例子。本例子將根據《Tree in MongoDB》推薦的全路徑方法構建樹結構。

      首先要做的是一所示的操作頁面。

    

       圖一  操作頁面

      操作頁面很簡單,就是用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>("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)通過Regex查詢其子節點。在這裡因為要返回的只是父節點的下一級子節點,所以需要增加一個節點深度條件(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>("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");                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;    }

      因為使用全路徑的結構,所以刪除一個節點及其子節點變得相當簡單,只要通過該節點的全路徑,使用Regex搜尋到節點本身及其子節點就行了。在例子中使用以下語句就輕鬆完成了刪除操作:

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");                    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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.