mongodb之圖聚合查詢 之圖查詢$graphLookup

mongodb之圖聚合查詢 之圖查詢$graphLookup

官網的流程解釋:

$graphLookup

Performs a recursive search on a collection, with options for restricting the search by recursion depth and query filter.

The $graphLookup search process is summarized below:

  1. Input documents flow into the $graphLookup stage of an aggregation operation.

  2. $graphLookup targets the search to the collection designated by the from parameter (see below for full list of search parameters).

  3. For each input document, the search begins with the value designated by startWith. 對每個輸入的文檔,先用startWith來匹配。

  4. $graphLookup matches the startWith value against the field designated by connectToField in other documents in the from collection. startWith來匹配from文檔裏的connectToField。只是第一輪。後邊就不用startWith了

  5. For each matching document, $graphLookup takes the value of the connectFromField and checks every document in the from collection for a matching connectToField value. For each match, $graphLookup adds the matching document in the from collection to an array field named by the as parameter.當startWith與from中的文檔的connectToField匹配成功,就取connectFromField進行下一輪from裏的connectToField進行匹配,一直遞歸循環,直到最大深度。

    This step continues recursively until no more matching documents are found, or until the operation reaches a recursion depth specified by the maxDepth parameter. $graphLookup then appends the array field to the input document. $graphLookup returns results after completing its search on all input documents. 設置最大遞歸層次。

綜上進行如下流程:A join B join B join B join ...    其中A,B都是集合。是左外連接。也就是A中的文檔會全部會留下來。

//集合A與集合B進行連接
for(docA in A){
    dfs_join(docA.startWith, B, 0); //初始時使用startWith作爲第一個值
}
//深度優先搜索
void dfs_join(docConnectFromField, B, deep){
     if(deep > maxDeep){    //超過最大深度就退出
         return;
     }
     for(docB in B){   //對B中的每個文檔的connectToField與輸入的docConnectFromField比較
        if(docConnectFromField == docB.connectToField){
            as.insert(docB); //匹配成功,保存dockB到as指定的數組裏
            dfs_join(docB.connectFromField, B, deep+1); //拿出docB的connectFromField繼續進行匹配
        }
     }
}
{
   $graphLookup: {
      from: <collection>,
      startWith: <expression>,
      connectFromField: <string>,
      connectToField: <string>,
      as: <string>,
      maxDepth: <number>,
      depthField: <string>,
      restrictSearchWithMatch: <document>
   }
}
//查入數據
db.mp.insertMany([ 
{"val":1, "name":"A", "tar":["B","C"]},
{"val":2, "name":"B", "tar":["D","E"]},
{"val":3, "name":"C", "tar":["E","F"]},
{"val":4, "name":"D", "tar":["F","A"]}
])

db.src.insertMany([
{"uname":"A", "age":28, "addr":"shenzheng"},
{"uname":"B", "age":30, "addr":"hangzhou"}
])

//startWith是src.uname==mp.name(connectToField), 匹配成功後,取mp.tar(connectFromField)再與mp中的每個文檔的name(connectToField)進行匹配,匹配成功後,取mptar....
//聚合
db.src.aggregate([
{
    "$match":{
        "age":{
            "$gte":20
         },
        "uname":{
            "$exists":1
        }
    }
},{
    "$graphLookup":{
        "from":"mp",
        "startWith":"$uname",
        "connectFromField":"tar", //這裏tar是個數組,那麼就用每個元素分別進行匹配
        "connectToField":"name",
        "as":"next",
        "maxDepth":10
    }
},
{
    "$project":{
        "_id":0,
        "uname":1,
        "next.name":1,
        "next.tar":1
    }
}
])
//查詢結果
{ "uname" : "A", "next" : [ { "name" : "B", "tar" : [ "D", "E" ] }, { "name" : "C", "tar" : [ "E", "F" ] }, { "name" : "A", "tar" : [ "B", "C" ] }, { "name" : "D", "tar" : [ "F", "A" ] } ] }
{ "uname" : "B", "next" : [ { "name" : "B", "tar" : [ "D", "E" ] }, { "name" : "C", "tar" : [ "E", "F" ] }, { "name" : "A", "tar" : [ "B", "C" ] }, { "name" : "D", "tar" : [ "F", "A" ] } ] }

注意,as(next)裏的數據是沒順序的。最後uname=A的next構成如下圖。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章