2017-10-11 8 views
5

mongodb 집계 쿼리를 사용하여 두 개의 컬렉션을 조인 ($ lookup) 한 다음 조인 된 배열의 모든 고유 값을 고유하게 계산하려고합니다. * 참고 : 필자는 metaDataMap 배열에 어떤 필드 (키)가 있는지 알 필요가 없습니다. 그리고지도에 존재하거나 존재하지 않을 수있는 필드를 세거나 포함하고 싶지 않습니다. 그래서 집계 쿼리는 그렇게 보이는 것입니다.Mongodb 집계 파이프 라인 크기 및 속도 문제

그래서 내 두 컬렉션은 다음과 같이 : events-

{ 
"_id" : "1", 
"name" : "event1", 
"objectsIds" : [ "1", "2", "3" ], 
} 

{ 
"_id" : "1", 
"name" : "object1", 
"metaDataMap" : { 
        "SOURCE" : ["ABC", "DEF"], 
        "DESTINATION" : ["XYZ", "PDQ"], 
        "TYPE" : [] 
       } 
}, 
{ 
"_id" : "2", 
"name" : "object2", 
"metaDataMap" : { 
        "SOURCE" : ["RST", "LNE"], 
        "TYPE" : ["text"] 
       } 
}, 
{ 
"_id" : "3", 
"name" : "object3", 
"metaDataMap" : { 
        "SOURCE" : ["NOP"], 
        "DESTINATION" : ["PHI", "NYC"], 
        "TYPE" : ["video"] 
       } 
} 

개체 내 결과는 내가 지금까지 가지고하는 것은 이것이다

{ 
_id:"SOURCE", count:5 
_id:"DESTINATION", count: 4 
_id:"TYPE", count: 2 
} 

있습니다

db.events.aggregate([ 
{$match: {"_id" : id}} 

,{$lookup: {"from" : "objects", 
     "localField" : "objectsIds", 
     "foreignField" : "_id", 
     "as" : "objectResults"}} 

,{$unwind: "$objectResults"} //Line 1 
,{$project: {x: "$objectResults.metaDataMap"}} //Line 2 


,{$unwind: "$x"} 
,{$project: {"_id":0}} 

,{$project: {x: {$objectToArray: "$x"}}} 
,{$unwind: "$x"} 

,{$group: {_id: "$x.k", tmp: {$push: "$x.v"}}} 

,{$addFields: {tmp: {$reduce:{ 
input: "$tmp", 
initialValue:[], 
in:{$concatArrays: [ "$$value", "$$this"]} 
    }} 
}} 

,{$unwind: "$tmp"} 
,{$group: {_id: "$_id", uniqueVals: {$addToSet: "$tmp"}}} 

,{$addFields: {count: {"$size":"$uniqueVals"}}} 
,{$project: {_id: "$_id", count: "$count"}} 
]); 

내 문제는 내가 1 행을 표시했다. & 2. 위의 작업은 metaDataMap 배열 필드 (objectsResults.metaDataMap)에서 25,000 개의 값으로 약 50 초가 걸린다. 예를 들어 객체 1의 metaDataMap 소스 배열에 25,000 개의 값이있는 경우를 예로들 수 있습니다. 그것은 천천히가는 길입니다. 그것을 할 내 다른 빠른 방법은 함께 1 & 2 라인을 교체했다 : (3 초 미만)이 빠른 방법입니다

,{$project: {x: "$objectResults.metaDataMap"}} //Line 1 
,{$unwind: "$x"} //Line 2 

만 ~ 10,000 항목 이하가 데이터 세트에서 실행할 수 있습니다. 더 높은 값을 지정하면 "최대 문서 크기 초과"라는 오류 메시지가 나타납니다.

도와주세요!

+0

"다양한 배열의 25,000 개 항목"에 대해 더 자세한 설명을 추가 할 수 있습니까? –

+1

그냥 생각. 'metaDataMap' 구조체를''metaDataMap': [ "k": { "SOURCE", "v": [ "ABC", "DEF"]} ...]'로 변경하고' $ map' 단계가'$ lookup' 다음에 있습니다. '{ "$ project": "{{$ map": { "input": "object"} " { "input": "$$ resultom", "as": "resultim", "in": { "k": "$$ resultim.k", "v": {\t "$ size": \t "$ $ resultim.v "}}}}}}}}}'. 나는 당신이 크기를 얻을 수 있고 푸는 것이 더 빠를 수 있어야한다고 믿습니다. – Veeram

+0

하지만 크기가 뚜렷하지 않습니다. 나는? 나는 v 값을 뺄 필요가있다. – Deckard

답변

0

당신이 parent_id 필드를 포함하는 object 컬렉션 스키마 설계를 변경 할 수 있다면, 당신은 즉시 파이프 라인의 첫 번째 4 단계 (첫 번째 $match, $lookup, $unwind$project)를 제거 할 수 있습니다. 그러면 Line 1Line 2에 대한 우려가 사라집니다.

{ 
    "_id": "1", 
    "name": "object1", 
    "metaDataMap": { 
    "SOURCE": [ 
     "ABC", 
     "DEF" 
    ], 
    "DESTINATION": [ 
     "XYZ", 
     "PDQ" 
    ], 
    "TYPE": [ ] 
    }, 
    "parent_id": "1" 
} 

은 따라서 당신이 비싼 $lookup$unwind 필요하지 않습니다 : 같은

예를 들어, object 컬렉션의 문서가 보일 것이다. 처음 4 단계는 다음으로 대체 할 수 있습니다

db.objects.aggregate([ 
    {$match: {parent_id: id}} 
    ,{$project: {metaDataMap: {$filter: {input: {$objectToArray: '$metaDataMap'}, cond: {$ne: [[], '$$this.v']}}}}} 
    ,{$unwind: '$metaDataMap'} 
    ,{$unwind: '$metaDataMap.v'} 
    ,{$group: {_id: '$metaDataMap.k', val: {$addToSet: '$metaDataMap.v'}}} 
    ,{$project: {count: {$size: '$val'}}} 
]) 

이 출력됩니다 :

{ "_id": "TYPE", "count": 2 } 
{ "_id": "DESTINATION", "count": 4 } 
{ "_id": "SOURCE", "count": 5 } 
이 아이디어를 바탕으로

{$match: {parent_id: id}} 

, 나는 결과 파이프 라인의 더 최적화했다