आप इसे किसी भी तरह से देखते हैं, जब तक आपके पास इस तरह के सामान्यीकृत संबंध हैं, तो आपको "कार्य" संग्रह से विवरण और "प्रोजेक्ट" संग्रह से विवरण भरने के परिणाम प्राप्त करने के लिए दो प्रश्नों की आवश्यकता होगी। मोंगोडीबी किसी भी तरह से जुड़ने का उपयोग नहीं करता है, और नेवला अलग नहीं है। नेवला .populate()
. की पेशकश करता है , लेकिन यह केवल सुविधा जादू है जो अनिवार्य रूप से एक और क्वेरी चला रहा है और संदर्भित फ़ील्ड मान पर परिणामों को मर्ज कर रहा है।
तो यह एक ऐसा मामला है जहां शायद आप अंततः परियोजना की जानकारी को कार्य में एम्बेड करने पर विचार कर सकते हैं। निश्चित रूप से दोहराव होगा, लेकिन यह एकल संग्रह के साथ क्वेरी पैटर्न को और अधिक सरल बनाता है।
संग्रह को एक संदर्भित मॉडल से अलग रखते हुए आप मूल रूप से दो दृष्टिकोण रखते हैं। लेकिन सबसे पहले आप aggregate का इस्तेमाल कर सकते हैं अपनी वास्तविक आवश्यकताओं के अनुसार अधिक परिणाम प्राप्त करने के लिए:
Task.aggregate(
[
{ "$group": {
"_id": "$projectId",
"completed": {
"$sum": {
"$cond": [ "$completed", 1, 0 ]
}
},
"incomplete": {
"$sum": {
"$cond": [ "$completed", 0, 1 ]
}
}
}}
],
function(err,results) {
}
);
यह केवल एक $group
का उपयोग करता है
"कार्य" संग्रह के भीतर "प्रोजेक्टिड" के मूल्यों पर जमा करने के लिए पाइपलाइन। "पूर्ण" और "अपूर्ण" के मानों की गणना करने के लिए हम $cond
ऑपरेटर जो यह तय करने के लिए एक टर्नरी है कि कौन सा मान $sum
. चूंकि यहां पहली या "अगर" स्थिति एक बूलियन मूल्यांकन है, तो मौजूदा बूलियन "पूर्ण" फ़ील्ड काम करेगा, जहां true
से गुजरना होगा तीसरे तर्क को पारित करने के लिए "फिर" या "अन्य"।
वे परिणाम ठीक हैं लेकिन उनमें एकत्रित "_id" मानों के लिए "प्रोजेक्ट" संग्रह से कोई जानकारी नहीं है। आउटपुट को इस तरह दिखाने का एक तरीका है .populate()
. के मॉडल फॉर्म को कॉल करना एकत्रीकरण के भीतर से "परिणाम" ऑब्जेक्ट पर कॉलबैक परिणाम:
Project.populate(results,{ "path": "_id" },callback);
इस रूप में .populate()
कॉल एक ऑब्जेक्ट या डेटा की सरणी लेता है क्योंकि यह पहला तर्क है, दूसरा आबादी के लिए एक विकल्प दस्तावेज़ है, जहां अनिवार्य फ़ील्ड यहां "पथ" के लिए है। यह किसी भी आइटम को संसाधित करेगा और उस मॉडल से "पॉप्युलेट" करेगा जिसे कॉलबैक में परिणाम डेटा में उन ऑब्जेक्ट्स को सम्मिलित करने के लिए बुलाया गया था।
एक संपूर्ण उदाहरण सूची के रूप में:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
var projectSchema = new Schema({
"name": String
});
var taskSchema = new Schema({
"projectId": { "type": Schema.Types.ObjectId, "ref": "Project" },
"completed": { "type": Boolean, "default": false }
});
var Project = mongoose.model( "Project", projectSchema );
var Task = mongoose.model( "Task", taskSchema );
mongoose.connect('mongodb://localhost/test');
async.waterfall(
[
function(callback) {
async.each([Project,Task],function(model,callback) {
model.remove({},callback);
},
function(err) {
callback(err);
});
},
function(callback) {
Project.create({ "name": "Project1" },callback);
},
function(project,callback) {
Project.create({ "name": "Project2" },callback);
},
function(project,callback) {
Task.create({ "projectId": project },callback);
},
function(task,callback) {
Task.aggregate(
[
{ "$group": {
"_id": "$projectId",
"completed": {
"$sum": {
"$cond": [ "$completed", 1, 0 ]
}
},
"incomplete": {
"$sum": {
"$cond": [ "$completed", 0, 1 ]
}
}
}}
],
function(err,results) {
if (err) callback(err);
Project.populate(results,{ "path": "_id" },callback);
}
);
}
],
function(err,results) {
if (err) throw err;
console.log( JSON.stringify( results, undefined, 4 ));
process.exit();
}
);
और यह इस तरह के परिणाम देगा:
[
{
"_id": {
"_id": "54beef3178ef08ca249b98ef",
"name": "Project2",
"__v": 0
},
"completed": 0,
"incomplete": 1
}
]
तो .populate()
इस तरह के एकत्रीकरण परिणाम के लिए अच्छी तरह से काम करता है, यहां तक कि प्रभावी रूप से एक और क्वेरी, और आमतौर पर अधिकांश उद्देश्यों के लिए उपयुक्त होना चाहिए। हालांकि लिस्टिंग में एक विशिष्ट उदाहरण शामिल था जहां "दो" प्रोजेक्ट बनाए गए थे लेकिन निश्चित रूप से केवल "एक" कार्य केवल एक प्रोजेक्ट को संदर्भित करता था।
चूंकि एकत्रीकरण "कार्य" संग्रह पर काम कर रहा है, इसलिए इसे किसी भी "परियोजना" के बारे में कोई जानकारी नहीं है जो वहां संदर्भित नहीं है। परिकलित योग के साथ "परियोजनाओं" की पूरी सूची प्राप्त करने के लिए आपको दो प्रश्नों को चलाने और परिणामों को "विलय" करने में अधिक विशिष्ट होने की आवश्यकता है।
यह मूल रूप से अलग-अलग कुंजियों और डेटा पर "हैश मर्ज" है, हालांकि इसके लिए अच्छा सहायक nedb<नामक मॉड्यूल है। /ए> , जो आपको तर्क को MongoDB प्रश्नों और संचालन के साथ अधिक सुसंगत तरीके से लागू करने की अनुमति देता है।
मूल रूप से आप संवर्धित क्षेत्रों के साथ "प्रोजेक्ट्स" संग्रह से डेटा की एक प्रति चाहते हैं, फिर आप "विलय" या .update()
करना चाहते हैं वह जानकारी एकत्रीकरण परिणामों के साथ। फिर से प्रदर्शित करने के लिए पूरी सूची के रूप में:
var async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema,
DataStore = require('nedb'),
db = new DataStore();
var projectSchema = new Schema({
"name": String
});
var taskSchema = new Schema({
"projectId": { "type": Schema.Types.ObjectId, "ref": "Project" },
"completed": { "type": Boolean, "default": false }
});
var Project = mongoose.model( "Project", projectSchema );
var Task = mongoose.model( "Task", taskSchema );
mongoose.connect('mongodb://localhost/test');
async.waterfall(
[
function(callback) {
async.each([Project,Task],function(model,callback) {
model.remove({},callback);
},
function(err) {
callback(err);
});
},
function(callback) {
Project.create({ "name": "Project1" },callback);
},
function(project,callback) {
Project.create({ "name": "Project2" },callback);
},
function(project,callback) {
Task.create({ "projectId": project },callback);
},
function(task,callback) {
async.series(
[
function(callback) {
Project.find({},function(err,projects) {
async.eachLimit(projects,10,function(project,callback) {
db.insert({
"projectId": project._id.toString(),
"name": project.name,
"completed": 0,
"incomplete": 0
},callback);
},callback);
});
},
function(callback) {
Task.aggregate(
[
{ "$group": {
"_id": "$projectId",
"completed": {
"$sum": {
"$cond": [ "$completed", 1, 0 ]
}
},
"incomplete": {
"$sum": {
"$cond": [ "$completed", 0, 1 ]
}
}
}}
],
function(err,results) {
async.eachLimit(results,10,function(result,callback) {
db.update(
{ "projectId": result._id.toString() },
{ "$set": {
"complete": result.complete,
"incomplete": result.incomplete
}
},
callback
);
},callback);
}
);
},
],
function(err) {
if (err) callback(err);
db.find({},{ "_id": 0 },callback);
}
);
}
],
function(err,results) {
if (err) throw err;
console.log( JSON.stringify( results, undefined, 4 ));
process.exit();
}
और यहां परिणाम:
[
{
"projectId": "54beef4c23d4e4e0246379db",
"name": "Project2",
"completed": 0,
"incomplete": 1
},
{
"projectId": "54beef4c23d4e4e0246379da",
"name": "Project1",
"completed": 0,
"incomplete": 0
}
]
यह प्रत्येक "प्रोजेक्ट" के डेटा को सूचीबद्ध करता है और इसमें "कार्य" संग्रह से परिकलित मान शामिल होते हैं जो इससे संबंधित होते हैं।
तो कुछ उपाय हैं जो आप कर सकते हैं। दोबारा, आप अंततः "कार्य" को "प्रोजेक्ट" आइटम में एम्बेड करने से सबसे अच्छा हो सकते हैं, जो फिर से एक साधारण एकत्रीकरण दृष्टिकोण होगा। और यदि आप कार्य जानकारी को एम्बेड करने जा रहे हैं, तो आप "प्रोजेक्ट" ऑब्जेक्ट पर "पूर्ण" और "अपूर्ण" के लिए काउंटर बनाए रख सकते हैं और बस इन्हें अपडेट कर सकते हैं क्योंकि आइटम को कार्य सरणी में $inc
ऑपरेटर।
var taskSchema = new Schema({
"completed": { "type": Boolean, "default": false }
});
var projectSchema = new Schema({
"name": String,
"completed": { "type": Number, "default": 0 },
"incomplete": { "type": Number, "default": 0 }
"tasks": [taskSchema]
});
var Project = mongoose.model( "Project", projectSchema );
// cheat for a model object with no collection
var Task = mongoose.model( "Task", taskSchema, undefined );
// Then in later code
// Adding a task
var task = new Task();
Project.update(
{ "task._id": { "$ne": task._id } },
{
"$push": { "tasks": task },
"$inc": {
"completed": ( task.completed ) ? 1 : 0,
"incomplete": ( !task.completed ) ? 1 : 0;
}
},
callback
);
// Removing a task
Project.update(
{ "task._id": task._id },
{
"$pull": { "tasks": { "_id": task._id } },
"$inc": {
"completed": ( task.completed ) ? -1 : 0,
"incomplete": ( !task.completed ) ? -1 : 0;
}
},
callback
);
// Marking complete
Project.update(
{ "tasks": { "$elemMatch": { "_id": task._id, "completed": false } }},
{
"$set": { "tasks.$.completed": true },
"$inc": {
"completed": 1,
"incomplete": -1
}
},
callback
);
काउंटर अपडेट के सही ढंग से काम करने के लिए आपको वर्तमान कार्य स्थिति को जानना होगा, लेकिन इसके लिए कोड करना आसान है और आपके तरीकों में गुजरने वाली वस्तु में शायद आपके पास कम से कम वे विवरण होने चाहिए।
व्यक्तिगत रूप से मैं बाद के रूप में फिर से मॉडल करूंगा और ऐसा करूंगा। आप क्वेरी "विलय" कर सकते हैं जैसा कि यहां दो उदाहरणों में दिखाया गया है, लेकिन यह निश्चित रूप से एक लागत पर आता है।