2 क्षेत्रों की तुलना पर MongoDb क्वेरी स्थिति


108

मेरे पास T2 फ़ील्ड के साथ एक संग्रह है : Grade1और Grade2, और मैं शर्त के साथ उन लोगों का चयन करना चाहता Grade1 > Grade2हूं, जिन्हें MySQL में एक क्वेरी कैसे मिल सकती है?

Select * from T Where Grade1 > Grade2

जवाबों:


120

आप $ का उपयोग कहां कर सकते हैं। बस जागरूक रहें यह काफी धीमा होगा (प्रत्येक रिकॉर्ड पर जावास्क्रिप्ट कोड निष्पादित करना होगा) इसलिए यदि आप कर सकते हैं तो अनुक्रमित प्रश्नों के साथ गठबंधन करें।

db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );

या अधिक कॉम्पैक्ट:

db.T.find( { $where : "this.Grade1 > this.Grade2" } );

Mongodb v.3.6 + के लिए UPD

आप हाल के उत्तर$expr में वर्णित अनुसार उपयोग कर सकते हैं


उफ़, मैं इसे प्राप्त करता हूं, बस संयुक्त-उपयोग जावास्क्रिप्ट या अन्य शेल स्क्रिप्ट, आप दोनों लोगों को धन्यवाद!
डिएगो चेंग

16
आप इसे थोड़ा और कॉम्पैक्ट भी कर सकते हैं ...> db.T.find ({$ जहां: "this.Grade1> this.Grade2"});
जस्टिन जेनकिंस

मैं कैसे कर सकता था $where: function() { return this.Grade1 - this.Grade2 > variable }?
लुइस गोंजालेज

जब मैंने कोशिश की db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});कि यह कुछ भी नहीं लौटाए, यहां तक ​​कि संग्रह में डॉक्टर में से एक भी है ISODate("2017-01-20T10:55:08.000Z")। लेकिन <=और >=काम लगता है। कोई उपाय?
cateyes

@ cateyes थोड़ा देर से शायद ... लेकिन शुद्ध जावास्क्रिप्ट हमेशा गलत होता है जब = 2 तारीखों के बीच तुलना करें। हालांकि, मैंगो आपको प्रश्नों में तारीखों के बीच सटीक मिलान की खोज करने देता है। एक वर्कअराउंड .getTime () को मिलीसेकंड में बदलने के लिए या जो भी उपयोग कर रहा है:this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
leinaD_natipaC

53

नियमित क्वेरी में एकत्रीकरण कार्यों का उपयोग करने के लिए आप $ expr (3.6 mongo संस्करण ऑपरेटर) का उपयोग कर सकते हैं ।

query operatorsबनाम की तुलना करें aggregation comparison operators

नियमित क्वेरी:

db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})

एकत्रीकरण क्वेरी:

db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})

39

यदि आपकी क्वेरी में केवल $whereऑपरेटर शामिल हैं, तो आप केवल जावास्क्रिप्ट अभिव्यक्ति में पास कर सकते हैं:

db.T.find("this.Grade1 > this.Grade2");

अधिक प्रदर्शन के लिए, एक समग्र ऑपरेशन चलाएं $redactजिसमें दस्तावेज़ों को फ़िल्टर करने के लिए एक पाइपलाइन है जो दी गई स्थिति को पूरा करता है।

$redactपाइप लाइन की कार्यक्षमता को शामिल किया गया $projectऔर $matchक्षेत्र स्तर संपादकत्व जहां यह हालत मिलान का उपयोग कर सभी दस्तावेजों वापस आ जाएगी लागू करने के लिए $$KEEPउन है कि का उपयोग कर से मेल नहीं खाते और पाइपलाइन परिणामों से निकाल देता $$PRUNEचर।


निम्नलिखित एकत्रीकरण ऑपरेशन को चलाना $whereबड़े संग्रह के लिए उपयोग करने की तुलना में अधिक कुशलता से दस्तावेजों को फ़िल्टर करता है क्योंकि यह जावास्क्रिप्ट मूल्यांकन के बजाय एक एकल पाइपलाइन और देशी मोंगोडीबी ऑपरेटरों का उपयोग करता है $where, जो क्वेरी को धीमा कर सकता है:

db.T.aggregate([
    {
        "$redact": {
            "$cond": [
                { "$gt": [ "$Grade1", "$Grade2" ] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    }
])

जो दो पाइपलाइनों को शामिल करने का अधिक सरलीकृत संस्करण है $projectऔर $match:

db.T.aggregate([
    {
        "$project": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
            "Grade1": 1,
            "Grade2": 1,
            "OtherFields": 1,
            ...
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

साथ MongoDB 3.4 और नए:

db.T.aggregate([
    {
        "$addFields": {
            "isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
        }
    },
    { "$match": { "isGrade1Greater": 1 } }
])

पिछले एक doesn't मेरे साथ काम करने लगते हैं। IsGrade1Grait फ़ील्ड को ठीक से जोड़ा और मूल्यांकन किया जाता है, लेकिन किसी कारण से क्वेरी सभी पंक्तियों से मेल खाती है, कोई फर्क नहीं पड़ता isGrade1Gitory का मूल्य। इस व्यवहार का कारण क्या हो सकता है? संपादित करें: कोई बात नहीं, मैं एक सरणी को एकत्र करने के लिए नहीं गुजर रहा था (), लेकिन एक पैरामीटर के रूप में प्रत्येक एकत्रीकरण खुद को याद किया।
ThatBrianDude 14

13

मामले में प्रदर्शन पठनीयता से अधिक महत्वपूर्ण है और जब तक आपकी स्थिति में सरल अंकगणितीय ऑपरेशन होते हैं, आप एकत्रीकरण पाइपलाइन का उपयोग कर सकते हैं। पहले, बाएं हाथ की स्थिति की गणना करने के लिए $ परियोजना का उपयोग करें (सभी क्षेत्रों को बाएं हाथ की ओर ले जाएं)। फिर एक स्थिर और फिल्टर के साथ तुलना करने के लिए $ मैच का उपयोग करें। इस तरह आप जावास्क्रिप्ट निष्पादन से बचते हैं। नीचे अजगर में मेरा परीक्षण है:

import pymongo
from random import randrange

docs = [{'Grade1': randrange(10), 'Grade2': randrange(10)} for __ in range(100000)]

coll = pymongo.MongoClient().test_db.grades
coll.insert_many(docs)

कुल का उपयोग करना:

%timeit -n1 -r1 list(coll.aggregate([
    {
        '$project': {
            'diff': {'$subtract': ['$Grade1', '$Grade2']},
            'Grade1': 1,
            'Grade2': 1
        }
    },
    {
        '$match': {'diff': {'$gt': 0}}
    }
]))

1 लूप, सर्वश्रेष्ठ 1: 192 एमएस प्रति लूप

खोज और $ का उपयोग करके जहां:

%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))

1 लूप, सर्वश्रेष्ठ 1: 4.54 प्रति लूप

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.