MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

पूरे दस्तावेज़ के साथ $lookup से सरणी में तत्वों की फ़िल्टर की गई संख्या प्राप्त करें

खोज करने वालों के लिए व्याख्या - विदेशी गणना

मूल रूप से उत्तर दिए गए से थोड़ा बेहतर है कि वास्तव में $लुकअप मोंगोडीबी 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 पैटर्न, जब तक आप $ को क्वेरी तर्क प्रदान कर सकते हैं, तब तक लुकअप सीधे।




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB GridFS फ़ाइल अपेक्षाकृत छोटी फ़ाइल के लिए बहुत बड़ी है

  2. MongoDB टेक्स्ट इंडेक्सिंग ऐरे ऑब्जेक्ट कॉलम

  3. mgo . के साथ एक प्रकार की मैपिंग लागू करें

  4. Node.js . का उपयोग करके MongoDB से अंतिम N रिकॉर्ड चुनें

  5. एक ही दस्तावेज़ के विभिन्न भागों पर काम कर रहे स्थितीय $?

© कॉपीराइट http://hi.sqldat.com सर्वाधिकार सुरक्षित