2015-08-31 7 views
5

से मिलान सभी वस्तुओं के सभी सरणी तत्वों गिनती मैं एक संग्रह है कि इस तरह की वस्तुओं पर गतिविधि के लॉग है:MongoDB मापदंड

{ 
    "_id" : ObjectId("55e3fd1d7cb5ac9a458b4567"), 
    "object_id" : "1", 
    "activity" : [ 
     { 
      "action" : "test_action", 
      "time" : ISODate("2015-08-31T00:00:00.000Z") 
     }, 
     { 
      "action" : "test_action", 
      "time" : ISODate("2015-08-31T00:00:22.000Z") 
     } 
    ] 
} 

{ 
    "_id" : ObjectId("55e3fd127cb5ac77478b4567"), 
    "object_id" : "2", 
    "activity" : [ 
     { 
      "action" : "test_action", 
      "time" : ISODate("2015-08-31T00:00:00.000Z") 
     } 
    ] 
} 

{ 
    "_id" : ObjectId("55e3fd0f7cb5ac9f458b4567"), 
    "object_id" : "1", 
    "activity" : [ 
     { 
      "action" : "test_action", 
      "time" : ISODate("2015-08-30T00:00:00.000Z") 
     } 
    ] 
} 

तो मैं followoing करते क्वेरी:

db.objects.find({ 
    "createddate": {$gte : ISODate("2015-08-30T00:00:00.000Z")}, 
    "activity.action" : "test_action"} 
    }).count() 

यह रिटर्न "test_action" (इस सेट में 3) वाले दस्तावेज़ों की गिनती, लेकिन मुझे सभी test_actions (4 इस सेट पर 4) की गिनती प्राप्त करने की आवश्यकता है। मैं उसको कैसे करू?

उत्तर

8

सबसे "performant" तरीका यह है $unwind altogther को छोड़ करने के लिए है और गिनने के लिए बस $group। अनिवार्य रूप से "फिल्टर" सरणियों $sum परिणामों के $size मिलती है:

db.objects.aggregate([ 
    { "$match": { 
     "createddate": { 
      "$gte": ISODate("2015-08-30T00:00:00.000Z") 
     }, 
     "activity.action": "test_action" 
    }}, 
    { "$group": { 
     "_id": null, 
     "count": { 
      "$sum": { 
       "$size": { 
        "$setDifference": [ 
         { "$map": { 
          "input": "$activity", 
          "as": "el", 
          "in": { 
           "$cond": [ 
            { "$eq": [ "$$el.action", "test_action" ] }, 
            "$$el", 
            false 
           ] 
          }    
         }}, 
         [false] 
        ] 
       } 
      } 
     } 
    }} 
]) 

MongoDB की भावी रिलीज़ $filter है, जो कि ज़्यादा से ज़्यादा सरल बना देता है होगा:

db.objects.aggregate([ 
    { "$match": { 
     "createddate": { 
      "$gte": ISODate("2015-08-30T00:00:00.000Z") 
     }, 
     "activity.action": "test_action" 
    }}, 
    { "$group": { 
     "_id": null, 
     "count": { 
      "$sum": { 
       "$size": { 
        "$filter": { 
         "input": "$activity", 
         "as": "el", 
         "cond": { 
          "$eq": [ "$$el.action", "test_action" ] 
         } 
        } 
       } 
      } 
     } 
    }} 
]) 

$unwind दस्तावेजों का उपयोग का कारण बनता है डी करने के लिए - सरणीकरण और प्रभावशाली प्रति प्रति प्रविष्टि एक प्रतिलिपि बनाता है। जहां संभव हो आप अक्सर अत्यधिक लागत के कारण इस से बचना चाहिए। प्रति दस्तावेज सरणी प्रविष्टियों को फ़िल्टर करना और गिनती करना तुलना करके बहुत तेज़ है। जैसा कि कई चरणों की तुलना में एक सरल $match और $group पाइपलाइन है।

+1

बहुत बहुत धन्यवाद। "$ Unwind" से बचने के लिए बड़े डेटासेट पर जरूरी है। प्रश्न एक आकर्षण की तरह काम करता है। मेरा ज्ञान अब काफी बुनियादी है और मुझे वास्तव में यह नहीं पता कि यह अभी तक कैसे काम करता है :) लेकिन इसे ढूंढना आज के लिए मेरा होमवर्क होगा) – aokozlov

5

आप एकत्रीकरण का उपयोग करके ऐसा कर सकते हैं:

db.objects.aggregate([ 
    {$match: {"createddate": {$gte : ISODate("2015-08-30T00:00:00.000Z")}, {"activity.action" : "test_action"}}}, 
    {$unwind: "$activity"}, 
    {$match: {"activity.action" : "test_action"}}}, 
    {$group: {_id: null, count: {$sum: 1}}} 
]) 

यह एक परिणाम का उत्पादन करेगा की तरह:

{ 
    count: 4 
} 
+0

धन्यवाद, यह काम करता है, लेकिन ऐसा लगता है कि यह इंडेक्स का उपयोग नहीं करता है और 600k दस्तावेज़ डेटासेट पर अत्यधिक धीमा काम करता है। मेरे पास '_id',' निर्मित दिनांक 'और 'गतिविधि.action' के लिए अनुक्रमणिका हैं। मुझे और क्या इंडेक्स बनाना चाहिए? – aokozlov

+0

एकत्रीकरण $ मैच चरण (यदि शुरुआत में निर्दिष्ट है) के लिए एक सूचकांक का उपयोग करता है, लेकिन जैसा कि ब्लैक सेवन ने कहा है, अनचाहे चरण बहुत अधिक ओवरहेड का कारण बनता है। – ZeMoon

+0

मैंने एक संपादन जोड़ा है, इसे थोड़ा तेज़ – ZeMoon