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
$graphLookup
stage of an aggregation operation. -
$graphLookup
targets the search to the collection designated by thefrom
parameter (see below for full list of search parameters). -
For each input document, the search begins with the value designated by
startWith
. 对每个输入的文档,先用startWith来匹配。 -
$graphLookup
matches thestartWith
value against the field designated byconnectToField
in other documents in thefrom
collection. startWith来匹配from文档里的connectToField。只是第一轮。后边就不用startWith了 -
For each matching document,
$graphLookup
takes the value of theconnectFromField
and checks every document in thefrom
collection for a matchingconnectToField
value. For each match,$graphLookup
adds the matching document in thefrom
collection to an array field named by theas
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构成如下图。