Istnieje kilka problemów z Twoją implementacją. Po pierwsze, używasz find()
niepoprawnie, ponieważ podajesz zbyt wiele argumentów dla zapytania:
MyModel.find(
{ Mkt_Al : Mkt_Air },
{ Orig : Origin },
{ Dest : Thru_Point },
{ Eff_Date : Effective_Date }
).lean().exec(function(err, docs) { .. }
powinno być
MyModel.find({
Mkt_Al: Mkt_Air,
Orig: Origin,
Dest: Thru_Point,
Eff_Date: Effective_Date
}).lean().exec(function(err, docs) { ... }
Ponownie, nie powinieneś używać find()
w tym przypadku, ponieważ potrzebujesz tylko jednego dokumentu, który pasuje do zapytania do użycia w obliczeniach. Biorąc złożony algorytm z poprzedniego pytania zamkniętego:
Korzystanie z MyModel.findOne()
powinno wystarczyć do zadań 3, 4 i 5 powyżej. Jednak ze względu na asynchroniczną naturę wywołań, konieczne byłoby zagnieżdżenie zapytań, ale na szczęście głębokość zagnieżdżonych wywołań nie jest większa niż 3, w przeciwnym razie znajdziesz się z biletem w jedną stronę do Callback Hell. Aby uniknąć tych typowych pułapek, lepiej użyć Promises
(ponieważ natywne zapytania dotyczące mangusty domyślnie mogą zwracać Promise
) lub użyj node-async
pakiet, który zawiera wiele funkcji do radzenia sobie z takimi sytuacjami.
Jeśli używasz async
bibliotekę, skutecznie pozwala na uruchamianie wielu zadań asynchronicznych (takich jak MyModel.findOne()
połączeń), które są od siebie zależne, a kiedy wszyscy skończą, zrób coś innego. W powyższym przykładzie możesz użyć async.series()
metoda.
Poniższy przykład ilustruje powyższą koncepcję, w której można obliczyć Qsi
z następujących przykładowych dokumentów w testowej bazie danych.
Wypełnij kolekcję testowej bazy danych vol:
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" : "",
}
])
Aplikacja Node.js:
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);
});
}
});
});
Przykładowe wyjście:
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
}