2013-04-23 68 views
7

我有一個類似的數據結構,因爲這:用貓鼬查詢得到的只有一個子文檔

var GrandGrandChild = mongoose.Schema({ 
    attribute: String, 
    id: Number 
}); 

var GrandChild = mongoose.Schema({ 
    children: [GrandGrandChild], 
    id: Number, 
    irrelevantAttribute: String 
}); 

var Child = mongoose.Schema({ 
    children: [GrandChild], 
    id: Number, 
    irrelevantAttribute2: String 
}); 

var Parent = mongoose.Schema({ 
    children: [Child], 
    id: Number, 
    irrelevantAttribute3: String 
}); 

var GrandParent = mongoose.Schema({ 
    children: [Parent], 
    id: Number, 
    irrelevantAttribute4: String 
}); 

這些都是很多收藏在他們的子文檔。 請注意,ID對於它們的兄弟姐妹是唯一的,但對於具有相同模式的所有元素不是唯一的。

所以一個盛大的父母可以有ID爲0的父母和祖父母的另一個也可以有父ID爲0,但一個祖父母不能有2位家長ID爲0

是被保存的唯一模式是GrandParent架構,並且mongoose/mongodb爲這個祖父母的所有數據創建了一個很好的大單文檔。 (正是我在找什麼)

所以這裏是我的問題:我有一個GrandParent ID,父ID,子ID,GrandChildID和GrandGrandChild ID,並且我想以某種方式只獲取所有這些ID的GrandGrandChild對象指向。

醜陋的方式是,但目前我可以開始工作的唯一方法是做一個查詢,獲取這個GrandParent的大文檔,並手動循環遍歷所有數組以找到正確的Parent,然後再次循環找到合適的孩子,然後再循環尋找合適的孫子,然後再次循環,找到需要在這裏工作的孫子女。

我的問題是,我將如何編寫一個查詢貓鼬,要麼只返回grandgrandchild文檔,或只包含子屬性的祖父文件,並在該屬性只有父對象包括引用子這指的是指grandgrandchild對象的孫子對象,允許其結果下列對象:

GRANDPARENT PARENT  CHILD  GRANDCHILD GRANDGRANDCHILD 
grandparent.children[0].children[0].children[0].children[0].attribute; 

我希望有人能幫助我在此查詢,就也是我得到的是這樣的:

GrandParentModel.findOne(
    { 
     "id" : 0, 
     "children.id" : 0, 
     "children.children.id" : 0, 
     "children.children.children.id" : 0, 
     "children.children.children.children.id" : 0 
    }, 
    {"children.children.children.children.$" : 1}, callback); 

這個查詢的問題是,unnessicary兄弟不是修剪掉。

我希望有人能幫助我。

Hylke勒布朗

回答

3

我問了這個問題已經有一段時間了,但我想我找到了一種相當優雅的方式來處理這些結構。

在這種情況下,我將展示它如何與只有GrandParent,父母和孩子一起工作。

而不是存儲每個文檔中的子文檔列表(GrandParent.children,Parent。兒童),我創建了以下結構的唯一標識符:

Child.referenceId = { 
    grandparent: "some key to the grandparent of the parent", 
    parent: "some key to the parent", 
    child: "key of this child" 
}; 

Parent.referenceId = { 
    grandparent: "some key to its grandparent", 
    parent: "key of this parent" 
} 

GrandParent.referenceId = { 
    grandparent: "key of this parent" 
} 

這會創建一個GrandParent> Parent> Child的層次結構。

該機型將類似於以下內容:

var idStructure = { 
    grandparent: { type: String, required: true }, 
    parent: { type: String, required: false }, 
    child: { type: String, required: false } 
}; 

var GrandParent = mongoose.Schema({ 
    id: idStructure, 
    irrelevantAttribute: String 
}); 

var Parent = mongoose.Schema({ 
    id: idSructure, 
    irrelevantAttribute: String 
}); 

var Child = mongoose.Schema({ 
    id: idStructure, 
    irrelevantAttribute: String 
}); 

注意父犯規直接知道其母公司,因爲他們並不像子文檔存儲。然而,通過referenceId,Parent和Child之間仍然存在關聯。

當祖父母的整個譜系圖搜索,一個只會執行3個查詢,然後正確地連接:

// First find all children which belong to the grandparent 
Child.find({"id.grandparent" : "some key to the grandparent"}) 
.exec(function(err, children) 
{ 
    if(err) 
     return; 

    Parent.find({"id.grandparent" : "some key to the grandparent"}) 
    .exec(function(err, parents) 
    { 
     if(err) 
      return; 

     // Loop through the parents and children to connect them before returning to a client 
     for(var i = 0; i < parents.length; i++) 
     { 
      var parent = parents[i]; 
      parent.children = []; 
      // loop through the children to check if they belong to the current parent 
      for(var j = 0; j < children.length; j++) 
      { 
       var child = children[j]; 
       if(parent.id.parent == child.id.parent) 
        parent.children.push(child); 
      } 
     } 

     // After filling the children into the parents, get the grandparents and do the same for the parents and grandparents as done for the children and parents. 
     GrandParent.find({"id.grandparent" : "some key to the grandparent"}) 
     .exec(function(err, grandparents) 
     { 
      // TODO: the same as done above (two loops, one loops the grandparents, other loops the parents 
      // Once this is finished, we have a filled grandparent 
     }); 

    }); 
}); 

上面的代碼將導致在短短的祖父母,充滿了父母,這是充滿了孩子。

原因沒有更多的祖父母會被發現是因爲grandParent的id應該是唯一的,因爲祖父母的referenceId只有祖父母的財產。

我希望我明確指出了自己的觀點,因爲通過這種方法,人們可以輕鬆地搜索一個特定的孩子,通過參考ID輕鬆獲取其父母,並通過參考ID輕鬆獲得其父母。

這可能有點複雜,但是一旦你爲自己想出了方法,它的所有方面都很簡單。

Hylke

+0

在YouTube上的一些相關視頻,其中一個關於[「基數最低原則」](https://www.youtube.com/watch?v=L994ZiVuSTE),另一個關於[存儲分層數據]示例(https ://www.youtube.com/watch v = T5Yt6Ndm2QY)。這來自一個關於EDX的Mongoose相關課程,名爲[「使用MEAN棧介紹MongoDB」](https://courses.edx.org/courses/course-v1:MongoDBx+M101x+3T2015/info) – 2015-12-25 05:52:13

2

是非常困難的事情在一個乾淨的方式工作,得到這樣。

我沒有在這個主題上找到一個乾淨的解決方案,但也許我可以幫助你循環的事情。 您可以使用以下方式避免循環: var doc = parent.children.id(id); Finding a sub-document

我希望這可以幫助您。 問候, 塞巴斯蒂安。

+0

但在這種情況下,我第一次獲得大文件,然後我從這個文件,我需要的所有字段選擇。相反,我只得到一個小的文件。我認爲使用大文檔處理小文檔會更快。 – 2013-10-24 11:49:52

0

這個工作對我來說

 model.find({_id:args.id},{ commentList: { $elemMatch: { _id: todo.commentList[todo.commentList.length-1] } } },(err, todos) => { 
     if (err) reject(err) 
     else resolve(todos) 
     console.log(todos); 
     }) 

$elemMatch (projection)