2017-06-07 80 views
1

我正在嘗試使用新的MongoDB v3.4 $ graphLookup聚合管道。我有這個簡單的樹集合,一些節點和父DBREF:

{ "_id" : ObjectId("59380657bbdbfb36c18a80f2"), "name" : "Root node 1" }, 
{ "_id" : ObjectId("5938068abbdbfb36c18a80f5"), "name" : "Child 1.1", "parent" : ObjectId("59380657bbdbfb36c18a80f2") }, 
{ "_id" : ObjectId("593806b0bbdbfb36c18a80f7"), "name" : "Subchild 1.1.1", "parent" : ObjectId("5938068abbdbfb36c18a80f5") }, 
{ "_id" : ObjectId("5938068abbdbfb36c18a80f6"), "name" : "Child 1.2", "parent" : ObjectId("59380657bbdbfb36c18a80f2") }, 
{ "_id" : ObjectId("59380657bbdbfb36c18a80f3"), "name" : "Root node 2" } 

我想獲得這種樹狀結構的:

- Root node 1 
    - Child 1.1 
     - Subchild 1.1.1 
    - Child 1.2 
- Root node 2 

所以,我試圖與工作新的$ graphLookup聚合管道,就像這樣:

db.getCollection('tree').aggregate([ 
    { $match: { parent: { $exists: false } } }, 
    { 
     $graphLookup: { 
      from: "tree", 
      startWith: "$_id", 
      connectFromField: "_id", 
      connectToField: "parent", 
      as: "children" 
     } 
    }, 
    { $sort: { name: 1 } } 
]) 

但我的問題是,我得到「根節點1」所有的孩子在一個收集:

{ 
    "_id" : ObjectId("59380657bbdbfb36c18a80f2"), 
    "name" : "Root node 1", 
    "children" : [ 
     { "_id" : ObjectId("593806b0bbdbfb36c18a80f7"), "name" : "Subchild 1.1.1", "parent" : ObjectId("5938068abbdbfb36c18a80f5") }, 
     { "_id" : ObjectId("5938068abbdbfb36c18a80f6"), "name" : "Child 1.2", "parent" : ObjectId("59380657bbdbfb36c18a80f2") }, 
     { "_id" : ObjectId("5938068abbdbfb36c18a80f5"), "name" : "Child 1.1", "parent" : ObjectId("59380657bbdbfb36c18a80f2") } 
    ] 
}, 
{ 
    "_id" : ObjectId("59380657bbdbfb36c18a80f3"), 
    "name" : "Root node 2", 
    "children" : [ ] 
} 

我不知道如何查找兒童遞歸獲得「兒童1.1」兒童集合中的「Subchild 1.1.1」。 我正在尋找任何建議。謝謝:)

回答

1

$graphLookup不產生依賴關係的層次結構 - 它執行連接文檔的遞歸搜索,但結果展平爲單維數組。下面是從文檔報價:

對於每一個匹配的文件,$ graphLookup採取 _id和檢查每一個文件的集合在 匹配的值的值。對於每場比賽,$ graphLookup將from from collection中的 匹配文檔添加到數組children。該步驟遞歸地繼續,直到找不到更多的 匹配文檔,或者直到操作達到由maxDepth參數指定的 遞歸深度。

I.e.它會遞歸地搜索相關文檔,但無論孩子的位置有多「深」,每個找到的文檔都會添加到父文檔的相同子數組中。


注 - 您沒有看到Child 1.1與其連接Subchild 1.1.1,因爲你是在match階段過濾掉這些文件:

{ $match: { parent: { $exists: false } } } 

僅選擇的文件不具有父 - "Root node 1""Root node 2"。如果您將刪除此過濾器,然後用他們的家屬的層次結構中所有其他文件將被退回:

{ 
    "name" : "Child 1.1", 
    "children" : [ 
     { "name" : "Subchild 1.1.1" } 
    ] 
}, 
{ 
    "name" : "Child 1.2" 
    "children" : [] 
}, 
{ 
    "name" : "Root node 1", 
    "children" : [ 
     { "name" : "Subchild 1.1.1" }, 
     { "name" : "Child 1.2" }, 
     { "name" : "Child 1.1" } 
    ] 
}, 
{ 
    "name" : "Root node 2", 
    "children" : [] 
}, 
{ 
    "name" : "Subchild 1.1.1" 
    "children" : [] 
} 

如果你不希望混合使用不同的獨生子女樹的「深度」的孩子數組,然後查看文檔中的有趣評論

將maxDepth字段設置爲0相當於一個非遞歸的 $查找搜索階段。

這意味着每個文檔都會將其所有直接子元素放入子元素數組中,然後在沒有任何進一步遞歸搜索的情況下停止查找。輸出將是

{ 
    "name" : "Child 1.1", 
    "children" : [ 
     { "name" : "Subchild 1.1.1" } 
    ] 
}, 
{ 
    "name" : "Child 1.2" 
    "children" : [] 
}, 
{ 
    "name" : "Root node 1", 
    "children" : [ 
     { "name" : "Child 1.2" }, 
     { "name" : "Child 1.1" } 
    ] 
}, 
{ 
    "name" : "Root node 2", 
    "children" : [] 
}, 
{ 
    "name" : "Subchild 1.1.1" 
    "children" : [] 
} 
+0

感謝您的非常完整的答案!你的解釋更加清楚:「它執行連接文檔的遞歸搜索,但結果被壓縮到單維數組中」。 所以基本上,$ graphLookup無法處理依賴關係的層次結構。如果我需要計算一個完整的樹結構,它不是適合的工具。我可以重新計算你在評論中提到的結果(沒有$匹配)或尋找另一個解決方案:) –

+0

@JeremyBarthe我添加了小的更新(關於maxDepth參數)。看起來這更接近你想達到的目標。至少不同級別的孩子不會混淆。 –

+0

感謝您的幫助! maxDepth在樹結構中絕對是一件有趣的事情。我認爲結論是我無法計算整個樹(我的意思是嵌套層次),但無論如何$ lookup和$ graphLookup是非常好的特性(它們在MongoDB中顯然缺少)。 –