Der er flere problemer med din implementering. For det første bruger du find()
metode forkert, da du angiver for mange argumenter for forespørgslen:
MyModel.find(
{ Mkt_Al : Mkt_Air },
{ Orig : Origin },
{ Dest : Thru_Point },
{ Eff_Date : Effective_Date }
).lean().exec(function(err, docs) { .. }
burde være
MyModel.find({
Mkt_Al: Mkt_Air,
Orig: Origin,
Dest: Thru_Point,
Eff_Date: Effective_Date
}).lean().exec(function(err, docs) { ... }
Igen, du bør ikke bruge find()
metode i dette tilfælde, fordi du kun har brug for et enkelt dokument, der matcher forespørgslen, der skal bruges i dine beregninger. Tager den komplekse algoritme fra dit tidligere lukkede spørgsmål:
Brug af MyModel.findOne()
skulle være tilstrækkeligt til opgave 3, 4 og 5 ovenfor. Men på grund af den asynkrone karakter af opkaldene, ville du være nødt til at indlejre forespørgslerne, men heldigvis er dybden af de indlejrede opkald ikke større end 3, ellers vil du finde dig selv med en enkeltbillet til Callback Hell. For at undgå disse almindelige faldgruber er det bedre at bruge Promises
(da de oprindelige mongoose-forespørgsler som standard kan returnere et løfte
) eller brug node-async
pakke, som indeholder en række funktioner til at håndtere situationer som denne.
Hvis du bruger async
bibliotek, giver det dig effektivt mulighed for at køre flere asynkrone opgaver (såsom MyModel.findOne()
opkald), der er afhængige af hinanden, og når de alle er færdige, gør noget andet. I ovenstående kan du bruge async.series()
metode.
Følgende eksempel viser ovenstående koncept, hvor du kan beregne Qsi
fra følgende eksempeldokumenter i testdb.
Udfyld test db's volumsamling:
db.vols.insert([
{
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 169,
"Block_Mins" : 230,
"Ops_Week" : 3,
"Orig" : "AGP",
"Dest" : "OTP",
"Thru_Point" : "",
},
{
"Mkt_Al" : "2G",
"Stops" : 1,
"Seats" : 260,
"Block_Mins" : 260,
"Ops_Week" : 2,
"Orig" : "CEK",
"Dest" : "IKT",
"Thru_Point" : "OVB",
},
{
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 140,
"Block_Mins" : 60,
"Ops_Week" : 2,
"Orig" : "BEK",
"Dest" : "OTP",
"Thru_Point" : "",
},
{
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 160,
"Block_Mins" : 90,
"Ops_Week" : 3,
"Orig" : "CEK",
"Dest" : "OVB",
"Thru_Point" : "",
},
{
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 60,
"Block_Mins" : 50,
"Ops_Week" : 3,
"Orig" : "OVB",
"Dest" : "IKT",
"Thru_Point" : "",
}
])
Node.js app:
var mongoose = require('mongoose'),
express = require('express'),
async = require('async'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var volSchema = new Schema({},{ strict: false, collection: 'vols' }),
Vol = mongoose.model("Vol", volSchema);
mongoose.set('debug', false);
mongoose.connection.on("open", function (err) {
if (err) throw err;
var bulkUpdateOps = Vol.collection.initializeUnorderedBulkOp(),
counter = 0;
Vol.find({}).lean().exec(function (err, docs) {
if (err) throw err;
var locals = {};
docs.forEach(function(doc) {
locals.c1 = 0.3728 + (0.00454 * doc.Seats);
locals.c3 = doc.Ops_Week;
if (doc.Stops == 1) {
async.series([
// Load doc with first leg first
function(callback) {
Vol.findOne({
Mkt_Al: doc.Mkt_Al,
Orig: doc.Orig,
Dest: doc.Dest
}).lean().exec(function (err, flight) {
if (err) return callback(err);
locals.first_leg = flight.Block_Mins;
callback();
});
},
// Load second leg doc
// (won't be called before task 1's "task callback"
// has been called)
function(callback) {
Vol.findOne({
Mkt_Al: doc.Mkt_Al,
Orig: doc.Thru_Point,
Dest: doc.Dest
}).lean().exec(function (err, flight) {
if (err) return callback(err);
locals.second_leg = flight.Block_Mins;
callback();
});
}
], function(err) { // This function gets called after the
// two tasks have called their "task callbacks"
if (err) throw err;
// Here locals will be populated with `first_leg`
// and `second_leg`
// Just like in the previous example
var total_flight = locals.second_leg + locals.first_leg;
locals.c2 = 0.03;
locals.c4 = Math.pow((doc.Block_Mins / total_flight), -0.675);
});
} else {
locals.c2 = 1;
locals.c4 = 1;
}
counter++;
console.log(locals);
bulkUpdateOps.find({ "_id" : doc._id }).updateOne({
"$set": {
"Qsi": (locals.c1 * locals.c2 * locals.c3 * locals.c4)
}
});
if (counter % 500 == 0) {
bulkUpdateOps.execute(function(err, result) {
if (err) throw err;
bulkUpdateOps = Vol.collection.initializeUnorderedBulkOp();
});
}
});
if (counter % 500 != 0) {
bulkUpdateOps.execute(function(err, result) {
if (err) throw err;
console.log(result.nModified);
});
}
});
});
Eksempeloutput:
db.vols.find()
/* 1 */
{
"_id" : ObjectId("5767e7549ebce6d574702221"),
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 169,
"Block_Mins" : 230,
"Ops_Week" : 3,
"Orig" : "AGP",
"Dest" : "OTP",
"Thru_Point" : "",
"Qsi" : 3.42018
}
/* 2 */
{
"_id" : ObjectId("5767e7549ebce6d574702222"),
"Mkt_Al" : "2G",
"Stops" : 1,
"Seats" : 260,
"Block_Mins" : 260,
"Ops_Week" : 2,
"Orig" : "CEK",
"Dest" : "IKT",
"Thru_Point" : "OVB",
"Qsi" : 3.1064
}
/* 3 */
{
"_id" : ObjectId("5767e7549ebce6d574702223"),
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 140,
"Block_Mins" : 60,
"Ops_Week" : 2,
"Orig" : "BEK",
"Dest" : "OTP",
"Thru_Point" : "",
"Qsi" : 2.0168
}
/* 4 */
{
"_id" : ObjectId("5767e7549ebce6d574702224"),
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 160,
"Block_Mins" : 90,
"Ops_Week" : 3,
"Orig" : "CEK",
"Dest" : "OVB",
"Thru_Point" : "",
"Qsi" : 3.2976
}
/* 5 */
{
"_id" : ObjectId("5767e7549ebce6d574702225"),
"Mkt_Al" : "2G",
"Stops" : 0,
"Seats" : 60,
"Block_Mins" : 50,
"Ops_Week" : 3,
"Orig" : "OVB",
"Dest" : "IKT",
"Thru_Point" : "",
"Qsi" : 1.9356
}