खोज करने वालों के लिए व्याख्या - विदेशी गणना
मूल रूप से उत्तर दिए गए से थोड़ा बेहतर है कि वास्तव में $लुकअप
मोंगोडीबी 3.6 से। यह वास्तव में "सब-पाइपलाइन" अभिव्यक्ति के भीतर "गिनती" कर सकता है, जो बाद में फ़िल्टरिंग और गिनती के लिए "सरणी" लौटने या यहां तक कि $अनविंड
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"let": { "id": "$_id" },
"pipeline": [
{ "$match": {
"originalLink": "",
"$expr": { "$eq": [ "$$id", "$_id" ] }
}},
{ "$count": "count" }
],
"as": "linkCount"
}},
{ "$addFields": {
"linkCount": { "$sum": "$linkCount.count" }
}}
])
वह नहीं जो मूल प्रश्न पूछ रहा था, लेकिन अब सबसे इष्टतम रूप में नीचे दिए गए उत्तर का हिस्सा है, निश्चित रूप से $lookup
कम करके "मिलान की गई संख्या" केवल . कर दिया गया है "सभी मिलान किए गए दस्तावेज़" के बजाय।
मूल
ऐसा करने का सही तरीका "linkCount"
. जोड़ना होगा $group
पर
मंच के साथ-साथ एक $first
मूल दस्तावेज़ के किसी भी अतिरिक्त फ़ील्ड पर "एकवचन" फ़ॉर्म प्राप्त करने के लिए जैसा कि "पहले" राज्य था $अनविंड
सरणी पर संसाधित किया गया था जो $lookup<का परिणाम था /कोड>
:
सभी विवरण
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$unwind": "$link" },
{ "$match": { "link.originalLink": "" } },
{ "$group": {
"_id": "$_id",
"partId": { "$first": "$partId" },
"link": { "$push": "$link" },
"linkCount": {
"$sum": {
"$size": {
"$ifNull": [ "$link.linkHistory", [] ]
}
}
}
}}
])
उत्पादन:
{
"_id" : ObjectId("594a6c47f51e075db713ccb6"),
"partId" : "f56c7c71eb14a20e6129a667872f9c4f",
"link" : [
{
"_id" : ObjectId("594b96d6f51e075db67c44c9"),
"originalLink" : "",
"emailGroupId" : ObjectId("594a6c47f51e075db713ccb6"),
"linkHistory" : [
{
"_id" : ObjectId("594b96f5f51e075db713ccdf")
},
{
"_id" : ObjectId("594b971bf51e075db67c44ca")
}
]
}
],
"linkCount" : 2
}
partId के आधार पर समूह करें
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$unwind": "$link" },
{ "$match": { "link.originalLink": "" } },
{ "$group": {
"_id": "$partId",
"linkCount": {
"$sum": {
"$size": {
"$ifNull": [ "$link.linkHistory", [] ]
}
}
}
}}
])
उत्पादन करता है
{
"_id" : "f56c7c71eb14a20e6129a667872f9c4f",
"linkCount" : 2
}
$unwindके साथ ऐसा करने का कारण यह है कोड>
और फिर एक $match
क्योंकि उस क्रम में जारी किए जाने पर MongoDB वास्तव में पाइपलाइन को कैसे संभालता है। $lookup
के साथ ऐसा ही होता है
जैसा कि "व्याख्या"
प्रदर्शित किया गया है ऑपरेशन से आउटपुट:
{
"$lookup" : {
"from" : "link",
"as" : "link",
"localField" : "_id",
"foreignField" : "emailGroupId",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"originalLink" : {
"$eq" : ""
}
}
}
},
{
"$group" : {
मैं $group
वाला हिस्सा छोड़ रहा हूं
उस आउटपुट में यह प्रदर्शित करने के लिए कि अन्य दो पाइपलाइन चरण "गायब" हो जाते हैं। ऐसा इसलिए है क्योंकि उन्हें में "रोल-अप" किया गया है। $लुकअप
दिखाए गए अनुसार पाइपलाइन चरण। यह वास्तव में है कि मोंगोडीबी इस संभावना से कैसे निपटता है कि बीएसओएन सीमा को $लुकअप
मूल दस्तावेज़ की एक सरणी में।
आप बारी-बारी से ऑपरेशन को इस तरह लिख सकते हैं:
सभी विवरण
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$addFields": {
"link": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"linkCount": {
"$sum": {
"$map": {
"input": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"as": "l",
"in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
}
}
}
}}
])
partId द्वारा समूहित करें
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$addFields": {
"link": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"linkCount": {
"$sum": {
"$map": {
"input": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
},
"as": "l",
"in": { "$size": { "$ifNull": [ "$$l.linkHistory", [] ] } }
}
}
}
}},
{ "$unwind": "$link" },
{ "$group": {
"_id": "$partId",
"linkCount": { "$sum": "$linkCount" }
}}
])
जिसका आउटपुट समान है लेकिन पहली क्वेरी से "भिन्न" है जिसमें $फ़िल्टर
यहां "बाद" लागू किया गया है सभी $lookup
के परिणाम
मूल दस्तावेज़ के नए सरणी में वापस आ जाते हैं।
इसलिए प्रदर्शन के संदर्भ में, इसे पहले तरीके से करना वास्तव में अधिक प्रभावी है और साथ ही "फ़िल्टरिंग से पहले" संभावित बड़े परिणाम सेट के लिए पोर्टेबल होना जो अन्यथा 16MB BSON सीमा को तोड़ देगा।
रुचि रखने वालों के लिए एक साइड-नोट के रूप में, MongoDB (संभवतः 3.6 और ऊपर) के भविष्य के रिलीज़ में आप $replaceRoot
$addFields
के बजाय
नए $mergeObjects
. के उपयोग के साथ पाइपलाइन ऑपरेटर। इसका लाभ "ब्लॉक" के रूप में है, हम "फ़िल्टर किए गए"
. घोषित कर सकते हैं सामग्री $let
के माध्यम से एक चर के रूप में
, जिसका अर्थ है कि आपको वही लिखने की आवश्यकता नहीं है $filter
"दो बार":
db.emailGroup.aggregate([
{ "$lookup": {
"from": "link",
"localField": "_id",
"foreignField": "emailGroupId",
"as": "link"
}},
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$$ROOT",
{ "$let": {
"vars": {
"filtered": {
"$filter": {
"input": "$link",
"as": "l",
"cond": { "$eq": [ "$$l.originalLink", "" ] }
}
}
},
"in": {
"link": "$$filtered",
"linkCount": {
"$sum": {
"$map": {
"input": "$$filtered.linkHistory",
"as": "lh",
"in": { "$size": { "$ifNull": [ "$$lh", [] ] } }
}
}
}
}
}}
]
}
}}
])
फिर भी ऐसा "फ़िल्टर" करने का सबसे अच्छा तरीका $lookup
संचालन इस समय $unwind<का उपयोग करके "अभी भी" है /कोड>
फिर $match
पैटर्न, जब तक आप $ को क्वेरी तर्क प्रदान कर सकते हैं, तब तक लुकअप
सीधे।