2015-06-25 3 views
6

मान लीजिए कि मेरे पास दो संग्रह हैं, A और Bदो अलग-अलग संरचित संग्रहों का अंतर प्राप्त करना

A निम्न रूप में सरल दस्तावेज शामिल हैं:

{ _id: '...', value: 'A', data: '...' } 
{ _id: '...', value: 'B', data: '...' } 
{ _id: '...', value: 'C', data: '...' } 
… 

B इस तरह नेस्टेड वस्तुओं में शामिल हैं:

{ _id: '...', values: [ 'A', 'B' ]} 
{ _id: '...', values: [ 'C' ]} 
… 

अब क्या हो सकता है वहाँ A में दस्तावेजों है कि द्वारा संदर्भित नहीं कर रहे हैं वह यह है कि B में कोई भी दस्तावेज़, या B में संदर्भित दस्तावेज़ हैं जो A में मौजूद नहीं हैं।

चलिए उन्हें "अनाथ" कहते हैं।

मेरा प्रश्न अब है: मैं उन अनाथ दस्तावेजों को सबसे कुशल तरीके से कैसे ढूंढूं? अंत में, मुझे उनकी _id फ़ील्ड की आवश्यकता है।

अब तक मैं unwind का इस्तेमाल किया है A "समतल" के लिए, और differenceWith function of Ramda का उपयोग कर अंतर की गणना, लेकिन यह काफी लंबा समय लगता है और, वास्तव में कुशल नहीं निश्चित है के रूप में मैं के बजाय ग्राहक पर सभी काम कर डेटाबेस में

मैंने देखा है कि मोंगोडीबी में $setDifference ऑपरेटर है, लेकिन मुझे इसे काम नहीं मिला।

क्या कोई मुझे सही दिशा में इंगित कर सकता है, Node.js का उपयोग करके इन समस्याओं को हल करने और डेटाबेस में काम के अधिकांश (सभी?) को चलाने के लिए कैसे कर सकता है? किसी भी संकेत की सराहना की जाती है :-)

+3

से बताया है 'आदेश में यह प्रयास करें:' वर myCursor = db.B.find(); var B = myCursor.hasNext()? myCursor.next(): शून्य; db.A.find ({value: {$ nin: B.values}}); उम्मीद है कि यह – karthick

+0

@ karthick.k मदद करता है बस मेरे लंबे और verbose जवाब पोस्ट करें! आपका समाधान बहुत बेहतर दिखता है! मैं अपना छोड़ दूंगा, क्योंकि यह दिखाता है कि इसे एकत्रीकरण पाइपलाइन के साथ कैसे किया जाए ... – cessor

+0

@cessor विभिन्न विचार और समाधान हमेशा अच्छे होते हैं :) – karthick

उत्तर

6

मोंगो डीबी में आप जो भी कोशिश कर रहे हैं उसके लिए आप एकत्रीकरण पाइपलाइन का उपयोग कर सकते हैं। यदि इससे मदद नहीं मिलती है तो आप MapReduce का उपयोग कर सकते हैं लेकिन यह थोड़ा और जटिल है।

इस उदाहरण के लिए मैंने दो संग्रह "टैग" और "पेपर" नाम दिए, जहां टैग्स को आपके उदाहरण में "बी" नाम दिया गया है, और कागजात "ए" होंगे।

सबसे पहले हमें वास्तव में मौजूद मानों का सेट मिलता है और दस्तावेज़ों का संदर्भ दे रहे हैं। इसके लिए, हम टैग संग्रह में प्रत्येक मान को फ़्लैट करते हैं और इसे एक साथ पैक करते हैं। अनविंडिंग 'मान' सरणी में प्रत्येक मान के लिए मूल _id के साथ एक दस्तावेज़ बनाता है। इस फ्लैट सूची को फिर याद किया जाता है और उनके आईडी को नजरअंदाज कर दिया जाता है।

var referenced_tags = db.tags.aggregate(
    {$unwind: '$values'}, 
    {$group: { 
     _id: '', 
     tags: { $push: '$values'} 
    } 
}); 

यह रिटर्न:

{ "_id" : "", "tags" : [ "A", "B", "C"] } 

इस सूची में सभी दस्तावेजों के सभी मानों का एक संग्रह है।

फिर, आप एक समान संग्रह बनाते हैं, जिसमें उपलब्ध दस्तावेजों के टैग का सेट होता है। यह, खोलना कदम की जरूरत नहीं है के बाद से _ id एक अदिश मूल्य (= नहीं एक सूची)

var papers = db.papers.aggregate(
    {$group: { 
     _id: '', 
     tags: {$push: '$value'} 
    } 
}); 

{ "_id" : "", "tags" : [ "A", "B", "C", "D"] } 

उपज आप पहले से ही देख सकते हैं, सेट है कि मैं में डाल से है डेटाबेस, आईडी "डी" के साथ ए में एक दस्तावेज़ (पेपर) प्रतीत होता है, जिसे टैग संग्रह में संदर्भित नहीं किया गया है और इससे पहले अनाथ है।

अब आप अंतर आप की तरह किसी भी तरह से सेट की गणना, यह धीमी गति से हो सकता है सकते हैं, लेकिन एक उदाहरण के रूप उपयुक्त है:

var a = referenced_tags.tags; 
var b = tags.tags; 
var delta = a.filter(function (v) { return b.indexOf(v) < 0; }); 

एक अगले कदम के रूप में, आप इन मूल्यों की तलाश द्वारा आईडी पा सकते हैं डेल्टा, और पेश केवल अपने आईडी में:

db.papers.find({'value' : {'$in': delta}}, {'_id': 1}) 

रिटर्निंग:

{ "_id" : ObjectId("558bd2...44f6a") } 

संपादित करें: हालांकि यह अच्छी तरह से दिखाता है कि इस समस्या को एकत्रीकरण ढांचे के साथ कैसे पहुंचाया जाए, यह एक व्यवहार्य समाधान नहीं है। एक भी, एकत्रीकरण की जरूरत नहीं है के बाद से MongoDB काफी चालाक है:

db.papers.find({'value' : {'$nin': tags.values }}, {'_id': 1}) 

टैग कहाँ

var cursor = db.tags.find(); 
var tags = cursor.hasNext() : cusor.next() : null; 

के रूप में @ karthick.k

+0

सबसे पहले: आपके विस्तृत उत्तर के लिए बहुत बहुत धन्यवाद :-)। मुझे मूल रूप से यह मिला, सिवाय इसके कि आप क्लाइंट पर सेट अंतर की गणना क्यों करते हैं, डेटाबेस में नहीं। क्या यह वास्तव में संभव है? –

+0

मैं इसे कमांड लाइन पर कर रहा था। मैं देखता हूं कि इस तरह से ऐसा करने के लिए यह बिल्कुल आवश्यक नहीं है, क्योंकि अंतिम ऑप टिप्पणी से पता चला है। यदि आप इसे कहीं भी स्वचालित रूप से चलाने के लिए थे, तो मैं इसे मानचित्र/कम करने में लागू करने की कोशिश करता हूं (यह मानते हुए कि आप केवल वही कर रहे हैं जो आप वास्तव में कर रहे हैं ...) - चूंकि आपने ट्विटर पर एकत्रीकरण के बारे में पूछा था, इसलिए मुझे प्राथमिकता मिली थी इसे इस तरह से करें, बहुत सारे ग्राहक/सर्वर आगे और आगे शामिल हैं ... एक व्यवहार्य समाधान नहीं है, लेकिन शायद एक सीखने का संदर्भ ... – cessor

+0

बहुत बढ़िया उत्तर +1 – karthick

संबंधित मुद्दे