mongodb之图聚合查询 之图查询$graphLookup
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:
- 
Input documents flow into the $graphLookupstage of an aggregation operation.
- 
$graphLookuptargets the search to the collection designated by thefromparameter (see below for full list of search parameters).
- 
For each input document, the search begins with the value designated by startWith. 对每个输入的文档,先用startWith来匹配。
- 
$graphLookupmatches thestartWithvalue against the field designated byconnectToFieldin other documents in thefromcollection. startWith来匹配from文档里的connectToField。只是第一轮。后边就不用startWith了
- 
For each matching document, $graphLookuptakes the value of theconnectFromFieldand checks every document in thefromcollection for a matchingconnectToFieldvalue. For each match,$graphLookupadds the matching document in thefromcollection to an array field named by theasparameter.当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 maxDepthparameter.$graphLookupthen appends the array field to the input document.$graphLookupreturns 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构成如下图。

 
                    
                 
 
  
  
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号