आपकी आवश्यकता के आधार पर, दृष्टिकोणों में से एक यह हो सकता है कि आप अपने स्कीमा को इस तरह से डिज़ाइन करें कि प्रत्येक दस्तावेज़ में क्षमता हो एक से अधिक दस्तावेज़ रखने और अपने आप में एक कैप्ड कंटेनर . के रूप में कार्य करने के लिए ।
{
"_id":Number,
"doc":Array
}
संग्रह का प्रत्येक दस्तावेज़ कैप्ड कंटेनर . के रूप में कार्य करेगा , और दस्तावेज़ों को doc
. में सरणी के रूप में संग्रहीत किया जाएगा खेत। doc
फ़ील्ड एक सरणी होने के कारण, सम्मिलन के क्रम को बनाए रखेगा। आप दस्तावेज़ों की संख्या को n
तक सीमित कर सकते हैं . तो _id
प्रत्येक कंटेनर दस्तावेज़ का क्षेत्र n
. द्वारा वृद्धिशील होगा , एक कंटेनर दस्तावेज़ में रखे जा सकने वाले दस्तावेज़ों की संख्या को दर्शाता है।
ऐसा करने से आप से बचें extra fields
जोड़ना दस्तावेज़ के लिए, extra indices
, unnecessary sorts
।
पहला रिकॉर्ड सम्मिलित करना
यानी जब संग्रह खाली हो।
var record = {"name" : "first"};
db.col.insert({"_id":0,"doc":[record]});
बाद के रिकॉर्ड सम्मिलित करना
- अंतिम कंटेनर दस्तावेज़ के
_id
की पहचान करें , औरnumber
उसके पास जो दस्तावेज हैं। - यदि उसके पास जितने दस्तावेज़ हैं, वह
n
. से कम है , फिर अपडेट करें नए दस्तावेज़ के साथ कंटेनर दस्तावेज़, अन्यथा बनाएं एक नया कंटेनरदस्तावेज़।
मान लें, कि प्रत्येक container document
5
पकड़ सकते हैं अधिक से अधिक दस्तावेज़, और हम एक नया दस्तावेज़ सम्मिलित करना चाहते हैं।
var record = {"name" : "newlyAdded"};
// using aggregation, get the _id of the last inserted container, and the
// number of record it currently holds.
db.col.aggregate( [ {
$group : {
"_id" : null,
"max" : {
$max : "$_id"
},
"lastDocSize" : {
$last : "$doc"
}
}
}, {
$project : {
"currentMaxId" : "$max",
"capSize" : {
$size : "$lastDocSize"
},
"_id" : 0
}
// once obtained, check if you need to update the last container or
// create a new container and insert the document in it.
} ]).forEach( function(check) {
if (check.capSize < 5) {
print("updating");
// UPDATE
db.col.update( {
"_id" : check.currentMaxId
}, {
$push : {
"doc" : record
}
});
} else {
print("inserting");
//insert
db.col.insert( {
"_id" : check.currentMaxId + 5,
"doc" : [ record ]
});
}
})
ध्यान दें कि aggregation
, सर्वर साइड पर चलता है और बहुत कुशल है, यह भी ध्यान दें कि aggregation
आपको एक दस्तावेज़ लौटाएगा कर्सर . के बजाय संस्करणों में previous to 2.6
. तो आपको उपरोक्त कोड को संशोधित करने की आवश्यकता होगी ताकि कर्सर को पुनरावृत्त करने के बजाय केवल एक दस्तावेज़ से चयन किया जा सके।
दस्तावेज़ों के बीच में एक नया दस्तावेज़ सम्मिलित करना
अब, यदि आप दस्तावेज़ों के बीच एक नया दस्तावेज़ सम्मिलित करना चाहते हैं 1
और 2
, हम जानते हैं कि दस्तावेज़ _id=0
. के साथ कंटेनर के अंदर आना चाहिए और second
. में रखा जाना चाहिए doc
. में स्थिति उस कंटेनर की सरणी।
इसलिए, हम $each
. का उपयोग करते हैं और $position
विशिष्ट पदों में डालने के लिए ऑपरेटरों।
var record = {"name" : "insertInMiddle"};
db.col.update(
{
"_id" : 0
}, {
$push : {
"doc" : {
$each : [record],
$position : 1
}
}
}
);
ओवर फ्लो को संभालना
अब, हमें overflowing
दस्तावेजों की देखभाल करने की आवश्यकता है प्रत्येक container
. में , मान लें कि हम बीच में _id=0
. के साथ कंटेनर में एक नया दस्तावेज़ सम्मिलित करते हैं . अगर कंटेनर में पहले से ही 5
है दस्तावेज़, हमें move the last document to the next container
. की आवश्यकता है और ऐसा तब तक करें जब तक कि सभी कंटेनर अपनी क्षमता के भीतर दस्तावेज़ धारण न कर लें, यदि आवश्यक हो तो अंत में हमें अतिप्रवाह वाले दस्तावेज़ों को रखने के लिए एक कंटेनर बनाने की आवश्यकता है।
यह जटिल ऑपरेशन चाहिए सर्वर साइड . पर किया जाए . इसे संभालने के लिए, हम एक स्क्रिप्ट बना सकते हैं जैसे नीचे दी गई और register
यह मोंगोडब के साथ।
db.system.js.save( {
"_id" : "handleOverFlow",
"value" : function handleOverFlow(id) {
var currDocArr = db.col.find( {
"_id" : id
})[0].doc;
print(currDocArr);
var count = currDocArr.length;
var nextColId = id + 5;
// check if the collection size has exceeded
if (count <= 5)
return;
else {
// need to take the last doc and push it to the next capped
// container's array
print("updating collection: " + id);
var record = currDocArr.splice(currDocArr.length - 1, 1);
// update the next collection
db.col.update( {
"_id" : nextColId
}, {
$push : {
"doc" : {
$each : record,
$position : 0
}
}
});
// remove from original collection
db.col.update( {
"_id" : id
}, {
"doc" : currDocArr
});
// check overflow for the subsequent containers, recursively.
handleOverFlow(nextColId);
}
}
ताकि after every insertion in between
, हम इस function
. को लागू कर सकते हैं कंटेनर आईडी पास करके, handleOverFlow(containerId)
।
सभी रिकॉर्ड को क्रम में लाया जा रहा है
बस $unwind
का उपयोग करें aggregate pipeline
में ऑपरेटर ।
db.col.aggregate([{$unwind:"$doc"},{$project:{"_id":0,"doc":1}}]);
दस्तावेजों का पुन:आदेश देना
आप प्रत्येक दस्तावेज़ को एक कैप्ड कंटेनर में "_id" फ़ील्ड के साथ संग्रहीत कर सकते हैं:
.."doc":[{"_id":0,","name":"xyz",...}..]..
कैप्ड कंटेनर के "doc" एरे को पकड़ें, जिसके आइटम्स को आप फिर से ऑर्डर करना चाहते हैं।
var docArray = db.col.find({"_id":0})[0];
उनकी आईडी अपडेट करें ताकि सॉर्ट करने के बाद आइटम का क्रम बदल जाए।
सरणी को उनके _ids के आधार पर क्रमबद्ध करें।
docArray.sort( function(a, b) {
return a._id - b._id;
});
नए दस्तावेज़ सरणी के साथ कैप्ड कंटेनर को वापस अपडेट करें।
लेकिन फिर, सब कुछ उबलता है कि कौन सा दृष्टिकोण संभव है और आपकी आवश्यकता के अनुरूप सर्वोत्तम है।
आपके प्रश्नों पर आ रहा है:
Arrays के रूप में दस्तावेज़।
$each
का उपयोग करें और $position
db.collection.update()
में ऑपरेटर्स मेरे उत्तर में दर्शाए अनुसार कार्य करें।
हाँ। यह प्रदर्शन को प्रभावित करेगा, जब तक कि संग्रह में बहुत कम डेटा न हो।
हाँ। कैप्ड संग्रह के साथ, आप डेटा खो सकते हैं।