2017-10-11 14 views
5

Tôi đang cố sử dụng truy vấn tập hợp mongodb để kết hợp ($ lookup) hai bộ sưu tập và sau đó phân biệt tất cả các giá trị duy nhất trong mảng được nối. * Lưu ý: Tôi không nhất thiết phải biết các trường (khóa) nào nằm trong mảng metaDataMap. Và tôi không muốn đếm hoặc bao gồm các trường có thể hoặc không tồn tại trong Bản đồ. Vì vậy, đó là lý do tại sao truy vấn tổng hợp trông giống như vậy.Kích thước đường ống tập hợp Mongodb và vấn đề tốc độ

Vì vậy, hai bộ sưu tập của tôi trông như thế này: events-

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

Objects

{ 
"_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"] 
       } 
} 

kết quả của tôi là

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

Những gì tôi có cho đến nay là thế này:

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"}} 
]); 

Vấn đề của tôi là tôi đã đánh dấu dòng 1 & 2. Các tác phẩm trên nhưng mất khoảng 50 giây cho 25.000 giá trị trong các trường mảng metaDataMap (objectsResults.metaDataMap). Vì vậy, ví dụ như có một giá trị 25.000 trong mảng đối tượng 1 metaDataMap SOURCE. Đó là cách để làm chậm. My cách khác nhanh hơn để làm điều đó là để thay thế dòng 1 & 2 với:

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

Đây là cách nhanh hơn (dưới 3 giây) nhưng chỉ có thể chạy trên bộ dữ liệu có ~ 10.000 mặt hàng hoặc ít hơn. Bất cứ điều gì cao hơn và tôi nhận được một lỗi nói rằng "vượt quá kích thước tài liệu tối đa".

Vui lòng trợ giúp!

+0

Có thể thêm một chút mô tả về "25.000 mục trong các mảng khác nhau"? –

+1

Chỉ là một ý nghĩ. Có thể bạn có thể thử thay đổi cấu trúc 'metaDataMap' thành' "metaDataMap": ["k": {"SOURCE", "v": ["ABC", "DEF"]} ...] 'và chèn' Giai đoạn $ map' sau '$ lookup'. Một cái gì đó như '{" $ project ": {" data ": {" $ map ": {" input ":" $ objectResults.metaDataMap "," as ":" resultom "," in ": {" $ map ": {"input": "$$ resultom", "as": "resultim", "in": {"k": "$$ resultim.k", "v": {\t "$ size": \t "$ $ resultim.v "}}}}}}}}'. Tôi tin rằng cách này bạn có thể nhận được kích thước và thư giãn nên được nhanh hơn. – Veeram

+0

Nhưng tôi sẽ không nhận được một số khác biệt với kích thước. Tôi sẽ Tôi cần phải dedupe các giá trị v. – Deckard

Trả lời

0

Nếu bạn có thể thay đổi thiết kế giản đồ của bạn về việc thu object để bao gồm một lĩnh vực parent_id, bạn ngay lập tức có thể loại bỏ 4 giai đoạn đầu tiên của đường ống của bạn (là người đầu tiên $match, $lookup, $unwind$project). Điều này sẽ làm cho mối quan ngại về số Line 1Line 2 biến mất.

Ví dụ, một tài liệu trong bộ sưu tập object sẽ trông như thế:

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

Vì vậy bạn không cần phải đắt $lookup$unwind. 4 giai đoạn đầu tiên sau đó có thể được thay thế bằng:

{$match: {parent_id: id}} 

Dựa trên ý tưởng này, tôi đã tiếp tục tối ưu hóa các đường ống dẫn, dẫn đến:

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'}}} 
]) 

chí đầu ra này:

{ "_id": "TYPE", "count": 2 } 
{ "_id": "DESTINATION", "count": 4 } 
{ "_id": "SOURCE", "count": 5 } 
Các vấn đề liên quan