2012-11-02 16 views
32

मैं MongoDB में एक संग्रह है, जहां चारों ओर देखते हैं (~ 3 मिलियन रिकॉर्ड) है। मेरे नमूना रिकॉर्ड देखने की तरह,Mongodb में एक कुंजी के आधार पर डुप्लिकेट को कैसे हटाएं?

{ "_id" = ObjectId("50731xxxxxxxxxxxxxxxxxxxx"), 
    "source_references" : [ 
          "_id" : ObjectId("5045xxxxxxxxxxxxxx"), 
          "name" : "xxx", 
          "key" : 123 
          ] 
} 

मैं एक ही source_references.key होने संग्रह में डुप्लिकेट रिकॉर्ड की एक बहुत कुछ हो रहा है होगा। (डुप्लिकेट से मेरा मतलब है, source_references.key_id नहीं)।

मैं पर source_references.key आधारित डुप्लिकेट रिकॉर्ड निकालना चाहते हैं, मैं प्रत्येक रिकॉर्ड को पार और रिकॉर्ड को दूर करता है, तो मौजूद है करने के लिए कुछ PHP कोड लिखने की सोच रहा हूँ।

वहाँ मोंगो आंतरिक कमांड लाइन में डुप्लिकेट निकालने के लिए एक रास्ता है?

उत्तर

67

आपको विश्वास है कि source_references.key की पहचान करता है रिकॉर्ड नकल कर रहे हैं, तो आप MongoDB 2.6 में dropDups:true सूचकांक निर्माण विकल्प के साथ एक अद्वितीय सूचकांक सुनिश्चित कर सकते हैं या पुराने:

db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true}) 

यह प्रत्येक source_references.key के लिए पहली अद्वितीय दस्तावेज़ रखेंगे मूल्य, और किसी भी बाद के दस्तावेज़ ड्रॉप जो अन्यथा एक डुप्लिकेट कुंजी उल्लंघन का कारण बन जाएगा।

महत्वपूर्ण सूचनाएं:

  • dropDups विकल्प removed in MongoDB 3.0 था, तो एक अलग दृष्टिकोण की आवश्यकता होगी। उदाहरण के लिए, आप एग्रीगेशन का उपयोग इस प्रकार सुझा सकते हैं: MongoDB duplicate documents even after adding unique key
  • source_references.key फ़ील्ड को खोने वाले किसी भी दस्तावेज़ को शून्य मान के रूप में माना जाएगा, इसलिए बाद वाले दस्तावेज़ गायब होने के बाद हटाए जाएंगे। आप sparse:true सूचकांक सृजन विकल्प जोड़ सकते हैं ताकि सूचकांक केवल एक source_references.key क्षेत्र के साथ दस्तावेजों पर लागू होता है।

स्पष्ट सावधानी: अपने डेटाबेस का बैकअप ले लो, और एक स्टेजिंग वातावरण में यह कोशिश पहले अगर आप अनायास ही डेटा हानि के बारे में चिंतित हैं।

+1

हाथ सभी डॉक्स – Erik

+0

हम केवल नवीनतम डुप्लिकेट नष्ट कर सकता हूँ में अनिवार्य किया जाना चाहिए? मैं बूढ़े लोगों को रखने के लिए पसंद करता हूं, मैं यह कैसे कर सकता हूं? – Sekai

+0

@ सेकाई: यदि आप नवीनतम डुप्लीकेट (या अधिक नियंत्रण रखते हैं) को हटाना चाहते हैं तो आपको डुप्लीकेट ढूंढने के लिए कुछ कस्टम स्क्रिप्ट/कोड लिखना होगा और आप किस दस्तावेज़ को हटाना चाहते हैं उसे काम करना होगा। – Stennie

8

जबकि @ Stennie के एक वैध जवाब है, यह एक ही रास्ता नहीं है। वास्तव में मोंगोडीबी मैनुअल आपको ऐसा करने के दौरान बहुत सावधान रहने के लिए कहता है। वहाँ दो अन्य विकल्प

  1. हैं MongoDB करते हैं कि आप using Map Reduce
  2. आप programatically करना के लिए जो कम कुशल है।
22

aggregation framework द्वारा डुप्लिकेट निकालें।

ए। यदि आप एक बार में हटाना चाहते हैं।

var duplicates = []; 

db.collectionName.aggregate([ 
    // discard selection criteria, You can remove "$match" section if you want 
    { $match: { 
    source_references.key: { "$ne": '' } 
    }}, 
    { $group: { 
    _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties 
    dups: { "$addToSet": "$_id" }, 
    count: { "$sum": 1 } 
    }}, 
    { $match: { 
    count: { "$gt": 1 } // Duplicates considered as count greater than one 
    }} 
])    // You can display result until this and check duplicates 
.forEach(function(doc) { 
    doc.dups.shift();  // First element skipped for deleting 
    doc.dups.forEach(function(dupId){ 
     duplicates.push(dupId); // Getting all duplicate ids 
     } 
    )  
}) 

// If you want to Check all "_id" which you are deleting else print statement not needed 
printjson(duplicates);  

// Remove all duplicates in one go  
db.collectionName.remove({_id:{$in:duplicates}}) 

बी। आप दस्तावेजों को एक-एक करके हटा सकते हैं।

db.collectionName.aggregate([ 
    // discard selection criteria, You can remove "$match" section if you want 
    { $match: { 
    source_references.key: { "$ne": '' } 
    }}, 
    { $group: { 
    _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties 
    dups: { "$addToSet": "$_id" }, 
    count: { "$sum": 1 } 
    }}, 
    { $match: { 
    count: { "$gt": 1 } // Duplicates considered as count greater than one 
    }} 
])    // You can display result until this and check duplicates 
.forEach(function(doc) { 
    doc.dups.shift();  // First element skipped for deleting 
    db.collectionName.remove({_id : {$in: doc.dups }}); // Delete remaining duplicates 
}) 
+0

क्या आप इस लाइन को '// बता सकते हैं। यदि आपका परिणाम" परिणाम "में प्रतिक्रिया प्राप्त कर रहा है तो अन्यथा" 0res35 "क्वेरी का उपयोग न करें। मुझे सिंटैक्स त्रुटि मिल रही है 'सिंटेक्स त्रुटि: अप्रत्याशित टोकन। – Vaulstein

+1

मोंगोडब में पुराने संस्करण या Robomongo, मैं परिणाम वस्तु में आउटपुट प्राप्त कर रहा था। मुझे आशा है कि आप नए संस्करण का उपयोग कर रहे हैं और आपको इसकी आवश्यकता नहीं होगी। अद्यतन उत्तर –

+1

हाँ, यह 'db.things.ensureIndex ({'source_references.key': 1}, {unique: true, dropDups: true}) से बहुत आसान है, 'मैं पूरी तरह से समझता हूं कि उन्होंने यह सुनिश्चित क्यों किया कि इंडेक्स ...... ............... (◟; 益; ◞) – wordsforthewise

34

यह सबसे आसान क्वेरी मैं अपने MongoDB पर इस्तेमाल 3,2

db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){ 
    db.myCollection.remove({_id:{$gt:doc._id}, myCustomKey:doc.myCustomKey}); 
}) 

सूचकांक है अपने customKey इस गति को बढ़ाने के चलाने से पहले

+0

सबसे आसान और वास्तव में सरल होगा !!! – Jaydeep

+0

यदि मेरे पास अधिक डुप्लीकेट हैं तो इसका मतलब है कि यह सभी डुप्लीकेट – sara

+0

हां @ सारा को हटा देगा। जब तक आप हटाए गए प्रश्न –

0

mongo_remove_duplicate_indexes स्थापित पिप

  1. एक स्क्रिप्ट बनाने किसी भी भाषा में
  2. आपके संग्रह पर पुनरावृत्त
  3. नया संग्रह बनाएं और इस संग्रह में अनन्य सेट के साथ इस संग्रह में नई अनुक्रमणिका बनाएं, याद रखें कि यह इंडेक्स आपके मूल संग्रह में डुप्लिकेट को उसी नाम के साथ डुप्लिकेट को हटाना चाहता है, उसी नाम के साथ पूर्व- आपके पास एक संग्रह गेमिंग है, और इस संग्रह में आपके पास फ़ील्ड शैली है जिसमें डुप्लीकेट हैं, जिन्हें आप निकालना चाहते हैं, इसलिए बस नया संग्रह बनाएं db.createCollection ("cname") नई अनुक्रमणिका बनाएं db.cname.createIndex ({ 'शैली': 1}, अद्वितीय: 1) अब जब यू समान शैली केवल पहले स्वीकार किया जाएगा, अन्य duplicae कुंजी त्रुटि के साथ अस्वीकार कर दिया जाएगा साथ दस्तावेज़ डाल देगा
  4. अब सिर्फ json प्रारूप मूल्यों यू मैं प्राप्त सम्मिलित nto नया संग्रह और हैंडलिंग अपवाद पूर्व pymongo.errors.DuplicateKeyError के लिए

जांच बेहतर समझ

0

के लिए mongo_remove_duplicate_indexes के लिए पैकेज स्रोत कोड का उपयोग कर आप पर्याप्त स्मृति है, तो अपवाद को संभालने, आप स्केला में कर सकते हैं ऐसा ही कुछ:

cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id) 
.foreach(x=>cole.remove({id $eq x}) 
0

यहाँ यह करने का एक से थोड़ा अधिक 'मैनुअल' तरीका है:

अनिवार्य रूप से, पहले, आप रुचि रखते हैं कि सभी अद्वितीय कुंजी की एक सूची प्राप्त करें।

फिर उन प्रत्येक कुंजी का उपयोग करके एक खोज करें और हटाएं कि क्या यह खोज एक से अधिक बड़ी हो जाती है। इस तरह स्पष्टीकरण पर

db.collection.distinct("key").forEach((num)=>{ 
     var i = 0; 
     db.collection.find({key: num}).forEach((doc)=>{ 
     if (i) db.collection.remove({key: num}, { justOne: true }) 
     i++ 
     }) 
    });