मैं (MongoDB में) एक संग्रह में कई संग्रहों के डेटा को कैसे संयोजित कर सकता हूं?
क्या मैं मैप-कम का उपयोग कर सकता हूं और यदि हां तो कैसे?
मैं कुछ उदाहरणों की बहुत सराहना करूंगा क्योंकि मैं नौसिखिया हूं।
मैं (MongoDB में) एक संग्रह में कई संग्रहों के डेटा को कैसे संयोजित कर सकता हूं?
क्या मैं मैप-कम का उपयोग कर सकता हूं और यदि हां तो कैसे?
मैं कुछ उदाहरणों की बहुत सराहना करूंगा क्योंकि मैं नौसिखिया हूं।
जवाबों:
यद्यपि आप यह वास्तविक समय नहीं कर सकते हैं, आप MongoDB 1.8+ मैप / कम / " http://www.mongodb.org/ " में "कम" आउट विकल्प का उपयोग करके डेटा को एक साथ मर्ज करने के लिए कई बार मानचित्र-कम चला सकते हैं । प्रदर्शन / DOCS / MapReduce # MapReduce-Outputoptions )। आपको दोनों संग्रहों में कुछ कुंजी रखने की आवश्यकता है जिसे आप एक _id के रूप में उपयोग कर सकते हैं।
उदाहरण के लिए, मान लीजिए कि आपके पास एक users
संग्रह और एक हैcomments
संग्रह है और आप एक नया संग्रह चाहते हैं जिसमें प्रत्येक टिप्पणी के लिए कुछ उपयोगकर्ता जनसांख्यिकीय जानकारी हो।
मान लीजिए कि users
संग्रह में निम्नलिखित क्षेत्र हैं:
और फिर comments
संग्रह में निम्नलिखित क्षेत्र हैं:
आप इस नक्शे को कम / कम करेंगे:
var mapUsers, mapComments, reduce;
db.users_comments.remove();
// setup sample data - wouldn't actually use this in production
db.users.remove();
db.comments.remove();
db.users.save({firstName:"Rich",lastName:"S",gender:"M",country:"CA",age:"18"});
db.users.save({firstName:"Rob",lastName:"M",gender:"M",country:"US",age:"25"});
db.users.save({firstName:"Sarah",lastName:"T",gender:"F",country:"US",age:"13"});
var users = db.users.find();
db.comments.save({userId: users[0]._id, "comment": "Hey, what's up?", created: new ISODate()});
db.comments.save({userId: users[1]._id, "comment": "Not much", created: new ISODate()});
db.comments.save({userId: users[0]._id, "comment": "Cool", created: new ISODate()});
// end sample data setup
mapUsers = function() {
var values = {
country: this.country,
gender: this.gender,
age: this.age
};
emit(this._id, values);
};
mapComments = function() {
var values = {
commentId: this._id,
comment: this.comment,
created: this.created
};
emit(this.userId, values);
};
reduce = function(k, values) {
var result = {}, commentFields = {
"commentId": '',
"comment": '',
"created": ''
};
values.forEach(function(value) {
var field;
if ("comment" in value) {
if (!("comments" in result)) {
result.comments = [];
}
result.comments.push(value);
} else if ("comments" in value) {
if (!("comments" in result)) {
result.comments = [];
}
result.comments.push.apply(result.comments, value.comments);
}
for (field in value) {
if (value.hasOwnProperty(field) && !(field in commentFields)) {
result[field] = value[field];
}
}
});
return result;
};
db.users.mapReduce(mapUsers, reduce, {"out": {"reduce": "users_comments"}});
db.comments.mapReduce(mapComments, reduce, {"out": {"reduce": "users_comments"}});
db.users_comments.find().pretty(); // see the resulting collection
इस बिंदु पर, आपके पास एक नया संग्रह होगा जिसे users_comments
मर्ज किया गया डेटा शामिल है और अब आप इसका उपयोग कर सकते हैं। इन कम किए गए संग्रहों में वे सभी हैं _id
जो आपके नक्शे कार्यों में महत्वपूर्ण थे और फिर सभी मूल्य अंदर की एक उप-वस्तु हैंvalue
कुंजी के - मान इन कम किए गए दस्तावेज़ों के शीर्ष स्तर पर नहीं हैं।
यह कुछ सरल उदाहरण है। आप इसे अधिक संग्रह के साथ दोहरा सकते हैं जितना आप कम संग्रह का निर्माण करना चाहते हैं। आप प्रक्रिया में डेटा का सारांश और एकत्रीकरण भी कर सकते हैं। संभवतः आप एक से अधिक कम करने वाले फ़ंक्शन को परिभाषित करेंगे क्योंकि मौजूदा फ़ील्ड्स को एकत्र करने और संरक्षित करने के लिए तर्क अधिक जटिल हो जाता है।
आप यह भी ध्यान देंगे कि अब एक सरणी में उस उपयोगकर्ता की सभी टिप्पणियों के साथ प्रत्येक उपयोगकर्ता के लिए एक दस्तावेज़ है। यदि हम एक-से-एक के बजाय एक-से-एक संबंध रखने वाले डेटा को मर्ज कर रहे थे, तो यह समतल होगा और आप बस इस तरह कम फ़ंक्शन का उपयोग कर सकते हैं:
reduce = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
यदि आप users_comments
संग्रह को समतल करना चाहते हैं तो यह प्रति टिप्पणी एक दस्तावेज़ है, इसके अतिरिक्त इसे चलाएं:
var map, reduce;
map = function() {
var debug = function(value) {
var field;
for (field in value) {
print(field + ": " + value[field]);
}
};
debug(this);
var that = this;
if ("comments" in this.value) {
this.value.comments.forEach(function(value) {
emit(value.commentId, {
userId: that._id,
country: that.value.country,
age: that.value.age,
comment: value.comment,
created: value.created,
});
});
}
};
reduce = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
db.users_comments.mapReduce(map, reduce, {"out": "comments_with_demographics"});
इस तकनीक को निश्चित रूप से मक्खी पर नहीं किया जाना चाहिए। यह क्रोन जॉब के लिए अनुकूल है या ऐसा कुछ है जो समय-समय पर मर्ज किए गए डेटा को अपडेट करता है। संभवतः आप ensureIndex
नए संग्रह पर चलना चाहते हैं, ताकि आप यह सुनिश्चित कर सकें कि आप इसके विरुद्ध शीघ्रता से प्रदर्शन कर सकते हैं (ध्यान रखें कि आपका डेटा अभी भी एक value
कुंजी के अंदर है , इसलिए यदि आप comments_with_demographics
टिप्पणी created
समय पर अनुक्रमित करना चाहते हैं, तो यह होगाdb.comments_with_demographics.ensureIndex({"value.created": 1});
users_comments
कोड के पहले खंड के बाद संग्रह gist.github.com/nolanamy/83d7fb6a9bf92482a1c4311ad9c78835
MongoDB 3.2 अब एक को कई लुकअप से $ लुकिंग एग्रीगेशन चरण के माध्यम से एक में डेटा को संयोजित करने की अनुमति देता है । एक व्यावहारिक उदाहरण के रूप में, यह बताता है कि आपके पास दो अलग-अलग संग्रहों में विभाजित पुस्तकों के बारे में डेटा है।
books
निम्नलिखित डेटा वाले पहले संग्रह को कहा जाता है :
{
"isbn": "978-3-16-148410-0",
"title": "Some cool book",
"author": "John Doe"
}
{
"isbn": "978-3-16-148999-9",
"title": "Another awesome book",
"author": "Jane Roe"
}
और दूसरा संग्रह, जिसे books_selling_data
निम्नलिखित डेटा कहा जाता है :
{
"_id": ObjectId("56e31bcf76cdf52e541d9d26"),
"isbn": "978-3-16-148410-0",
"copies_sold": 12500
}
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 720050
}
{
"_id": ObjectId("56e31ce076cdf52e541d9d29"),
"isbn": "978-3-16-148999-9",
"copies_sold": 1000
}
दोनों संग्रहों को मर्ज करने के लिए निम्नलिखित तरीके से $ लुकअप का उपयोग करने की बात है:
db.books.aggregate([{
$lookup: {
from: "books_selling_data",
localField: "isbn",
foreignField: "isbn",
as: "copies_sold"
}
}])
इस एकत्रीकरण के बाद, books
संग्रह निम्नलिखित की तरह दिखेगा:
{
"isbn": "978-3-16-148410-0",
"title": "Some cool book",
"author": "John Doe",
"copies_sold": [
{
"_id": ObjectId("56e31bcf76cdf52e541d9d26"),
"isbn": "978-3-16-148410-0",
"copies_sold": 12500
}
]
}
{
"isbn": "978-3-16-148999-9",
"title": "Another awesome book",
"author": "Jane Roe",
"copies_sold": [
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 720050
},
{
"_id": ObjectId("56e31ce076cdf52e541d9d28"),
"isbn": "978-3-16-148999-9",
"copies_sold": 1000
}
]
}
कुछ बातों पर ध्यान देना जरूरी है:
books_selling_data
तेज नहीं किया जा सकता है।इसलिए, एक निष्कर्ष के रूप में, यदि आप दोनों संग्रहों को समेकित करना चाहते हैं, तो इस मामले में, बेची गई कुल प्रतियों के साथ एक सपाट प्रतियां_होल्ड फ़ील्ड, आपको थोड़ा अधिक काम करना होगा, शायद एक मध्यस्थ संग्रह का उपयोग करना होगा, जो तब, हो $ बाहर अंतिम संग्रह करने के लिए।
$lookup
सभी "लोकलफिल्ड" और "फॉरेनफिल्ड" के बराबर "आइसबीएन" दोनों में नहीं होना चाहिए? "_id" और "isbn" नहीं है?
अगर मोंगोडब में कोई बल्क इंसर्ट नहीं है, तो हम सभी ऑब्जेक्ट्स को लूप करते हैं small_collection
और उन्हें एक-एक करके अंदर डालते हैं big_collection
:
db.small_collection.find().forEach(function(obj){
db.big_collection.insert(obj)
});
$ खोज के साथ बहुत बुनियादी उदाहरण।
db.getCollection('users').aggregate([
{
$lookup: {
from: "userinfo",
localField: "userId",
foreignField: "userId",
as: "userInfoData"
}
},
{
$lookup: {
from: "userrole",
localField: "userId",
foreignField: "userId",
as: "userRoleData"
}
},
{ $unwind: { path: "$userInfoData", preserveNullAndEmptyArrays: true }},
{ $unwind: { path: "$userRoleData", preserveNullAndEmptyArrays: true }}
])
यहाँ प्रयोग किया जाता है
{ $unwind: { path: "$userInfoData", preserveNullAndEmptyArrays: true }},
{ $unwind: { path: "$userRoleData", preserveNullAndEmptyArrays: true }}
के बजाय
{ $unwind:"$userRoleData"}
{ $unwind:"$userRoleData"}
क्योंकि {$ खोलना: "$ userRoleData"} यह खाली या 0 परिणाम देगा यदि $ लुकिंग के साथ कोई मिलान रिकॉर्ड नहीं मिला।
एक 'SQL यूनिअन' फैशन में MongoDB में यूनियनों को करना एक ही प्रश्न में लुकअप के साथ-साथ एकत्रीकरण का उपयोग करना संभव है। यहाँ मैंने एक उदाहरण का परीक्षण किया है जो MongoDB 4.0 के साथ काम करता है:
// Create employees data for testing the union.
db.getCollection('employees').insert({ name: "John", type: "employee", department: "sales" });
db.getCollection('employees').insert({ name: "Martha", type: "employee", department: "accounting" });
db.getCollection('employees').insert({ name: "Amy", type: "employee", department: "warehouse" });
db.getCollection('employees').insert({ name: "Mike", type: "employee", department: "warehouse" });
// Create freelancers data for testing the union.
db.getCollection('freelancers').insert({ name: "Stephany", type: "freelancer", department: "accounting" });
db.getCollection('freelancers').insert({ name: "Martin", type: "freelancer", department: "sales" });
db.getCollection('freelancers').insert({ name: "Doug", type: "freelancer", department: "warehouse" });
db.getCollection('freelancers').insert({ name: "Brenda", type: "freelancer", department: "sales" });
// Here we do a union of the employees and freelancers using a single aggregation query.
db.getCollection('freelancers').aggregate( // 1. Use any collection containing at least one document.
[
{ $limit: 1 }, // 2. Keep only one document of the collection.
{ $project: { _id: '$$REMOVE' } }, // 3. Remove everything from the document.
// 4. Lookup collections to union together.
{ $lookup: { from: 'employees', pipeline: [{ $match: { department: 'sales' } }], as: 'employees' } },
{ $lookup: { from: 'freelancers', pipeline: [{ $match: { department: 'sales' } }], as: 'freelancers' } },
// 5. Union the collections together with a projection.
{ $project: { union: { $concatArrays: ["$employees", "$freelancers"] } } },
// 6. Unwind and replace root so you end up with a result set.
{ $unwind: '$union' },
{ $replaceRoot: { newRoot: '$union' } }
]);
यहां बताया गया है कि यह कैसे काम करता है:
अपने डेटाबेस aggregate
के किसी भी संग्रह से तुरंत हटाएं जिसमें कम से कम एक दस्तावेज़ हो। यदि आप गारंटी नहीं दे सकते हैं कि आपके डेटाबेस का कोई भी संग्रह खाली नहीं होगा, तो आप इस मुद्दे को अपने डेटाबेस में बनाकर कुछ इस तरह का 'डमी' संग्रह बना सकते हैं जिसमें एक एकल खाली दस्तावेज़ हो, जो विशेष रूप से यूनियन क्वेरी करने के लिए होगा।
अपनी पाइपलाइन का पहला चरण बनाएं { $limit: 1 }
। यह संग्रह के सभी दस्तावेजों को पहले एक को छोड़कर छीन लेगा।
एक $project
चरण का उपयोग करके शेष दस्तावेज़ के सभी क्षेत्रों को पट्टी करें :
{ $project: { _id: '$$REMOVE' } }
आपके कुल में अब एक एकल, खाली दस्तावेज़ है। यह प्रत्येक संग्रह के लिए लुकअप जोड़ने का समय है जिसे आप एक साथ मिलाना चाहते हैं। आप उपयोग कर सकते हैं pipeline
कुछ विशिष्ट छानने करने के लिए क्षेत्र, या छोड़ localField
और foreignField
अशक्त रूप में पूरे संग्रह मिलान करने के लिए।
{ $lookup: { from: 'collectionToUnion1', pipeline: [...], as: 'Collection1' } },
{ $lookup: { from: 'collectionToUnion2', pipeline: [...], as: 'Collection2' } },
{ $lookup: { from: 'collectionToUnion3', pipeline: [...], as: 'Collection3' } }
अब आपके पास एक एकल दस्तावेज़ है जिसमें इस तरह के 3 सरणियाँ हैं:
{
Collection1: [...],
Collection2: [...],
Collection3: [...]
}
आप एकत्रीकरण ऑपरेटर $project
के साथ एक मंच का उपयोग करके उन्हें एक साथ एक एकल सरणी में विलय कर सकते हैं $concatArrays
:
{
"$project" :
{
"Union" : { $concatArrays: ["$Collection1", "$Collection2", "$Collection3"] }
}
}
अब आपके पास एक एकल दस्तावेज़ है, जिसमें एक ऐसा सरणी स्थित है जिसमें आपके संग्रह का संघ है। जो कुछ करना बाकी है, उसे अपने दस्तावेज़ को अलग-अलग दस्तावेज़ों में विभाजित करने के लिए एक $unwind
और एक $replaceRoot
चरण जोड़ना है :
{ $unwind: "$Union" },
{ $replaceRoot: { newRoot: "$Union" } }
Voilà। अब आपके पास एक परिणाम सेट है जिसमें वे संग्रह हैं जिन्हें आप एक साथ मिलाना चाहते थे। फिर आप इसे फ़िल्टर करने के लिए और चरण जोड़ सकते हैं, इसे क्रमबद्ध कर सकते हैं, स्किप () और सीमा () लागू कर सकते हैं। बहुत कुछ आप चाहते हैं।
एकत्रीकरण में कई संग्रह के लिए कई $ लुकअप का उपयोग करें
क्वेरी:
db.getCollection('servicelocations').aggregate([
{
$match: {
serviceLocationId: {
$in: ["36728"]
}
}
},
{
$lookup: {
from: "orders",
localField: "serviceLocationId",
foreignField: "serviceLocationId",
as: "orders"
}
},
{
$lookup: {
from: "timewindowtypes",
localField: "timeWindow.timeWindowTypeId",
foreignField: "timeWindowTypeId",
as: "timeWindow"
}
},
{
$lookup: {
from: "servicetimetypes",
localField: "serviceTimeTypeId",
foreignField: "serviceTimeTypeId",
as: "serviceTime"
}
},
{
$unwind: "$orders"
},
{
$unwind: "$serviceTime"
},
{
$limit: 14
}
])
परिणाम:
{
"_id" : ObjectId("59c3ac4bb7799c90ebb3279b"),
"serviceLocationId" : "36728",
"regionId" : 1.0,
"zoneId" : "DXBZONE1",
"description" : "AL HALLAB REST EMIRATES MALL",
"locationPriority" : 1.0,
"accountTypeId" : 1.0,
"locationType" : "SERVICELOCATION",
"location" : {
"makani" : "",
"lat" : 25.119035,
"lng" : 55.198694
},
"deliveryDays" : "MTWRFSU",
"timeWindow" : [
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32cde"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "06:00",
"closeTime" : "08:00"
},
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32cdf"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "09:00",
"closeTime" : "10:00"
},
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b0a3b7799c90ebb32ce0"),
"timeWindowTypeId" : "1",
"Description" : "MORNING",
"timeWindow" : {
"openTime" : "10:30",
"closeTime" : "11:30"
},
"accountId" : 1.0
}
],
"address1" : "",
"address2" : "",
"phone" : "",
"city" : "",
"county" : "",
"state" : "",
"country" : "",
"zipcode" : "",
"imageUrl" : "",
"contact" : {
"name" : "",
"email" : ""
},
"status" : "ACTIVE",
"createdBy" : "",
"updatedBy" : "",
"updateDate" : "",
"accountId" : 1.0,
"serviceTimeTypeId" : "1",
"orders" : [
{
"_id" : ObjectId("59c3b291f251c77f15790f92"),
"orderId" : "AQ18O1704264",
"serviceLocationId" : "36728",
"orderNo" : "AQ18O1704264",
"orderDate" : "18-Sep-17",
"description" : "AQ18O1704264",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 296.0,
"size2" : 3573.355,
"size3" : 240.811,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "BNWB020",
"size1" : 15.0,
"size2" : 78.6,
"size3" : 6.0
},
{
"ItemId" : "BNWB021",
"size1" : 20.0,
"size2" : 252.0,
"size3" : 11.538
},
{
"ItemId" : "BNWB023",
"size1" : 15.0,
"size2" : 285.0,
"size3" : 16.071
},
{
"ItemId" : "CPMW112",
"size1" : 3.0,
"size2" : 25.38,
"size3" : 1.731
},
{
"ItemId" : "MMGW001",
"size1" : 25.0,
"size2" : 464.375,
"size3" : 46.875
},
{
"ItemId" : "MMNB218",
"size1" : 50.0,
"size2" : 920.0,
"size3" : 60.0
},
{
"ItemId" : "MMNB219",
"size1" : 50.0,
"size2" : 630.0,
"size3" : 40.0
},
{
"ItemId" : "MMNB220",
"size1" : 50.0,
"size2" : 416.0,
"size3" : 28.846
},
{
"ItemId" : "MMNB270",
"size1" : 50.0,
"size2" : 262.0,
"size3" : 20.0
},
{
"ItemId" : "MMNB302",
"size1" : 15.0,
"size2" : 195.0,
"size3" : 6.0
},
{
"ItemId" : "MMNB373",
"size1" : 3.0,
"size2" : 45.0,
"size3" : 3.75
}
],
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b291f251c77f15790f9d"),
"orderId" : "AQ137O1701240",
"serviceLocationId" : "36728",
"orderNo" : "AQ137O1701240",
"orderDate" : "18-Sep-17",
"description" : "AQ137O1701240",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 28.0,
"size2" : 520.11,
"size3" : 52.5,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "MMGW001",
"size1" : 25.0,
"size2" : 464.38,
"size3" : 46.875
},
{
"ItemId" : "MMGW001-F1",
"size1" : 3.0,
"size2" : 55.73,
"size3" : 5.625
}
],
"accountId" : 1.0
},
{
"_id" : ObjectId("59c3b291f251c77f15790fd8"),
"orderId" : "AQ110O1705036",
"serviceLocationId" : "36728",
"orderNo" : "AQ110O1705036",
"orderDate" : "18-Sep-17",
"description" : "AQ110O1705036",
"serviceType" : "Delivery",
"orderSource" : "Import",
"takenBy" : "KARIM",
"plannedDeliveryDate" : ISODate("2017-08-26T00:00:00.000Z"),
"plannedDeliveryTime" : "",
"actualDeliveryDate" : "",
"actualDeliveryTime" : "",
"deliveredBy" : "",
"size1" : 60.0,
"size2" : 1046.0,
"size3" : 68.0,
"jobPriority" : 1.0,
"cancelReason" : "",
"cancelDate" : "",
"cancelBy" : "",
"reasonCode" : "",
"reasonText" : "",
"status" : "",
"lineItems" : [
{
"ItemId" : "MMNB218",
"size1" : 50.0,
"size2" : 920.0,
"size3" : 60.0
},
{
"ItemId" : "MMNB219",
"size1" : 10.0,
"size2" : 126.0,
"size3" : 8.0
}
],
"accountId" : 1.0
}
],
"serviceTime" : {
"_id" : ObjectId("59c3b07cb7799c90ebb32cdc"),
"serviceTimeTypeId" : "1",
"serviceTimeType" : "nohelper",
"description" : "",
"fixedTime" : 30.0,
"variableTime" : 0.0,
"accountId" : 1.0
}
}
मोंगोरेस्टोर में डेटाबेस में पहले से ही जो कुछ भी है उसके ऊपर संलग्न करने की यह विशेषता है, इसलिए इस व्यवहार का उपयोग दो संग्रह के संयोजन के लिए किया जा सकता है:
अभी तक यह कोशिश नहीं की, लेकिन यह नक्शे की तुलना में तेजी से प्रदर्शन कर सकता है / दृष्टिकोण को कम कर सकता है।
शुरू करते हुए Mongo 4.4
, हम नए $unionWith
एकत्रीकरण चरण को $group
नए $accumulator
ऑपरेटर के साथ जोड़कर एक एकत्रीकरण पाइपलाइन के भीतर इसे प्राप्त कर सकते हैं :
// > db.users.find()
// [{ user: 1, name: "x" }, { user: 2, name: "y" }]
// > db.books.find()
// [{ user: 1, book: "a" }, { user: 1, book: "b" }, { user: 2, book: "c" }]
// > db.movies.find()
// [{ user: 1, movie: "g" }, { user: 2, movie: "h" }, { user: 2, movie: "i" }]
db.users.aggregate([
{ $unionWith: "books" },
{ $unionWith: "movies" },
{ $group: {
_id: "$user",
user: {
$accumulator: {
accumulateArgs: ["$name", "$book", "$movie"],
init: function() { return { books: [], movies: [] } },
accumulate: function(user, name, book, movie) {
if (name) user.name = name;
if (book) user.books.push(book);
if (movie) user.movies.push(movie);
return user;
},
merge: function(userV1, userV2) {
if (userV2.name) userV1.name = userV2.name;
userV1.books.concat(userV2.books);
userV1.movies.concat(userV2.movies);
return userV1;
},
lang: "js"
}
}
}}
])
// { _id: 1, user: { books: ["a", "b"], movies: ["g"], name: "x" } }
// { _id: 2, user: { books: ["c"], movies: ["h", "i"], name: "y" } }
$unionWith
एकत्रीकरण पाइपलाइन में दस्तावेजों के भीतर दिए गए संग्रह से रिकॉर्ड को जोड़ती है। 2 यूनियन चरणों के बाद, हमारे पास पाइपलाइन के भीतर सभी उपयोगकर्ता, किताबें और फिल्में रिकॉर्ड हैं।
तब हम ऑपरेटर $group
द्वारा दस्तावेजों के कस्टम संचय की अनुमति देते $user
हुए वस्तुओं का संग्रह और संचय करते हैं $accumulator
क्योंकि वे समूहबद्ध हो जाते हैं:
accumulateArgs
।init
उस समूह को परिभाषित करता है जिसे हम समूह तत्वों के रूप में संचित करेंगे।accumulate
समारोह प्रदर्शन की अनुमति देता है एक रिकार्ड के साथ एक कस्टम कार्रवाई आदेश संचित राज्य का निर्माण करने में वर्गीकृत किया जा रहा है। उदाहरण के लिए, यदि आइटम को समूहीकृत किया जा रहा है book
, तो फ़ील्ड परिभाषित है, तो हम अपडेट करते हैंbooks
राज्य हिस्से को ।merge
का उपयोग दो आंतरिक अवस्थाओं को मिलाने के लिए किया जाता है। इसका उपयोग केवल शार्प किए गए समूहों पर चलने वाले एकत्रीकरण के लिए किया जाता है या जब ऑपरेशन मेमोरी सीमा से अधिक हो जाता है।हां आप यह कर सकते हैं: आज जो मैंने लिखा है, यह उपयोगिता कार्य करें:
function shangMergeCol() {
tcol= db.getCollection(arguments[0]);
for (var i=1; i<arguments.length; i++){
scol= db.getCollection(arguments[i]);
scol.find().forEach(
function (d) {
tcol.insert(d);
}
)
}
}
आप इस फ़ंक्शन को किसी भी संख्या के संग्रह में पास कर सकते हैं, पहला लक्ष्य एक होने वाला है। बाकी सभी संग्रह स्रोत हैं जिन्हें लक्ष्य एक में स्थानांतरित किया जाना है।
सांकेतिक टुकड़ा। सौजन्य-एक सहित ढेर अतिप्रवाह पर कई पोस्ट।
db.cust.drop();
db.zip.drop();
db.cust.insert({cust_id:1, zip_id: 101});
db.cust.insert({cust_id:2, zip_id: 101});
db.cust.insert({cust_id:3, zip_id: 101});
db.cust.insert({cust_id:4, zip_id: 102});
db.cust.insert({cust_id:5, zip_id: 102});
db.zip.insert({zip_id:101, zip_cd:'AAA'});
db.zip.insert({zip_id:102, zip_cd:'BBB'});
db.zip.insert({zip_id:103, zip_cd:'CCC'});
mapCust = function() {
var values = {
cust_id: this.cust_id
};
emit(this.zip_id, values);
};
mapZip = function() {
var values = {
zip_cd: this.zip_cd
};
emit(this.zip_id, values);
};
reduceCustZip = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
if ("cust_id" in value) {
if (!("cust_ids" in result)) {
result.cust_ids = [];
}
result.cust_ids.push(value);
} else {
for (field in value) {
if (value.hasOwnProperty(field) ) {
result[field] = value[field];
}
};
}
});
return result;
};
db.cust_zip.drop();
db.cust.mapReduce(mapCust, reduceCustZip, {"out": {"reduce": "cust_zip"}});
db.zip.mapReduce(mapZip, reduceCustZip, {"out": {"reduce": "cust_zip"}});
db.cust_zip.find();
mapCZ = function() {
var that = this;
if ("cust_ids" in this.value) {
this.value.cust_ids.forEach(function(value) {
emit(value.cust_id, {
zip_id: that._id,
zip_cd: that.value.zip_cd
});
});
}
};
reduceCZ = function(k, values) {
var result = {};
values.forEach(function(value) {
var field;
for (field in value) {
if (value.hasOwnProperty(field)) {
result[field] = value[field];
}
}
});
return result;
};
db.cust_zip_joined.drop();
db.cust_zip.mapReduce(mapCZ, reduceCZ, {"out": "cust_zip_joined"});
db.cust_zip_joined.find().pretty();
var flattenMRCollection=function(dbName,collectionName) {
var collection=db.getSiblingDB(dbName)[collectionName];
var i=0;
var bulk=collection.initializeUnorderedBulkOp();
collection.find({ value: { $exists: true } }).addOption(16).forEach(function(result) {
print((++i));
//collection.update({_id: result._id},result.value);
bulk.find({_id: result._id}).replaceOne(result.value);
if(i%1000==0)
{
print("Executing bulk...");
bulk.execute();
bulk=collection.initializeUnorderedBulkOp();
}
});
bulk.execute();
};
flattenMRCollection("mydb","cust_zip_joined");
db.cust_zip_joined.find().pretty();
आपको अपनी एप्लिकेशन परत में ऐसा करना होगा। यदि आप ORM का उपयोग कर रहे हैं, तो यह अन्य संग्रह में मौजूद संदर्भों को खींचने के लिए एनोटेशन (या कुछ समान) का उपयोग कर सकता है। मैंने केवल मॉर्फिया के साथ काम किया है , और @Reference
एनोटेशन को संदर्भित किए जाने पर संदर्भित इकाई प्राप्त होती है, इसलिए मैं इसे कोड में स्वयं करने से बचने में सक्षम हूं।
db.collection1.find().forEach(function(doc){db.collection2.save(doc)});
तो पर्याप्त है। कृपया अपने उपयोग किए गए ड्राइवर (जावा, php, ...) को निर्दिष्ट करें यदि आप मोंगो शेल का उपयोग नहीं करते हैं।