草庐IT

node.js - 根据条件从现有字段计算分数

coder 2023-10-30 原文

我正在使用 MongoDB 2.6.9 和 NodeJs 0.10.37,我有一个集合 vols,意思是航类。

> db.vols.findOne()
{
    "_id" : ObjectId("5717a5d4578f3f2556f300f2"),
    "Orig" : "AGP",
    "Dest" : "OTP",
    "Flight" : 126,
    "Routing" : "AGP-OTP",
    "Stops" : 0,
    "Seats" : 169,
    "Ops_Week" : 3,
    "Eff_Date" : "2016-04-14",
    "Mkt_Al" : "0B",
    "Dep_Time" : 1110,
    "Thru_Point" : "",
    "Arr_Time" : 1600,
    "Block_Mins" : 230

}

每份文件都是指航空公司完成的一次航类,并提供详细信息,例如,前一份文件是指直接完成的航类(Stops : 0)。但是下一个,飞机停了。

db.vols.findOne({Stops:1})
{
    "_id" : ObjectId("5717a5d4578f3f2556f301c5"),
    "Orig" : "CEK",
    "Dest" : "IKT",
    "Flight" : 7756,
    "Routing" : "KZN-CEK-OVB-IKT",
    "Stops" : 1,
    "Seats" : 70,
    "Ops_Week" : 2,
    "Eff_Date" : "2016-04-11",
    "Mkt_Al" : "2G",
    "Dep_Time" : 1655,
    "Thru_Point" : "OVB",
    "Arr_Time" : 140,
    "Block_Mins" : 345
}

重要:

每个 Airline 在每条路线( Origin - Destination )中都有一个 score

如何计算分数?

因此,我需要进行这些计算并将新字段“QSI”插入到我的集合 vols 中。

重要:

c4 中的平均运行时间意味着:

例如,我们有一个带停靠站的航类,比方说:从AC的航类由B,例如,整个航类60分钟,但是从AB是20分钟,从BC是20分钟,这个平均值应该在 40 分钟后返回。

我试过这个解决方案,但对于 c4 来说,事情看起来不太管用:

var mongoose = require('mongoose'),
    express  = require('express'),
    Schema   = mongoose.Schema;

mongoose.connect('mongodb://localhost/ramtest');

var volsSchema = new Schema({}, { strict : false, collection : 'vols' });
var MyModel    = mongoose.model("MyModel", volsSchema);

mongoose.set('debug', true);

mongoose.connection.on("open", function(err) {
  if (err) throw err;

  var bulkUpdateOps = MyModel.collection.initializeUnorderedBulkOp(),
      counter       = 0;

  MyModel.find({}).lean().exec(function(err, docs) {
    if (err) throw err;

    docs.forEach(function(doc) {
      // computations
      var c1, c2, c3, c4, qsi, first_leg, second_leg, total_flight;

      c1 = 0.3728 + (0.00454 * doc.Seats);
      c2 = (doc.Stops == 1) ? 0.03 : 1;
      c3 = doc.Ops_Week;

      if (doc.Stops == 1) {
        var Mkt_Air        = doc.Mkt_Al,
            Origin         = doc.Orig,
            Destination    = doc.Dest,
            Thru_Point     = doc.Thru_Point,
            Effective_Date = doc.Eff_Date,
            Block_Mins     = doc.Block_Mins;

        MyModel.find({ Mkt_Al : Mkt_Air }, { Orig : Origin }, { Dest : Thru_Point }, { Eff_Date : Effective_Date }).lean().exec(function(err, docs) {
          docs.forEach(function(doc) {
            var first_leg = doc.Block_Mins;
            MyModel.find({ Mkt_Al : Mkt_Air }, { Orig : Thru_Point }, { Dest : Destination }, { Eff_Date : Effective_Date }).lean().exec(function(err, docs) {
              docs.forEach(function(doc) {
                var second_leg = doc.Block_Mins, total_flight = second_leg + first_leg;
                c4 = Math.pow((Block_Mins / total_flight), -0.675);
                qsi = c1 * c2 * c3 * c4;
              }); // the end of docs.forEach(function (doc){
            }); // the end of MyModel.find..
          }); // the end of docs.forEach(function (doc){
        }); // the end of MyModel.find..
      } // end if
      else {
        c4 = 1;
      }

      qsi = c1 * c2 * c3 * c4;

      counter++;

      bulkUpdateOps.find({ "_id" : doc._id }).updateOne({
        "$set" : { "Qsi" : qsi }
      });

      if (counter % 500 == 0) {
        bulkUpdateOps.execute(function(err, result) {
          if (err) throw err;
          bulkUpdateOps = MyModel.collection.initializeUnorderedBulkOp();
          console.log(result);
          console.log(doc);
        });
      }

    });

    if (counter % 500 != 0) {
      bulkUpdateOps.execute(function(err, result) {
        if (err) throw err;
        console.log(result);
      });
    }
  });

  var app = express();
  app.listen(3000, function() {
    console.log('Ready to calculate and insert the QSI');
  });
});

问题:

我认为问题出在 MyModel.find 上,如果我在这条指令中丢失了数据...,我的 scoreStops = 0,但如果 Stops = 1,我的分数取值为 Nan,并且在像 callback(null, docs) 请问谁能帮忙??

我怎样才能实现上述目标?

最佳答案

您的实现存在多个问题。首先,您使用的是 find() 方法不正确,因为您为查询指定了太多参数:

MyModel.find(
    { Mkt_Al : Mkt_Air }, 
    { Orig : Origin }, 
    { Dest : Thru_Point }, 
    { Eff_Date : Effective_Date }
).lean().exec(function(err, docs) { .. }

应该是

MyModel.find({ 
    Mkt_Al: Mkt_Air, 
    Orig: Origin, 
    Dest: Thru_Point, 
    Eff_Date: Effective_Date 
}).lean().exec(function(err, docs) { ... }

同样,您不应该使用 find() 方法,因为您只需要一个与查询匹配的文档即可用于您的计算。从您之前关闭的问题中提取复杂的算法:

Now I want to calculate a score c4 and insert it into my collection :

To do that I should calculate a value c4 just like this :

1) First I verify for each document if ( Field2 == 1 ) if it's true I continue else it's simple c4 takes value 1.

2) Then I should make a loop "for" and see which document verify these conditions : doc.Field1 == this.Field1 && doc.Field6 == this.Field6 && doc.Field7 == this.Field8

3) Then I take doc.Field4 wich will be added to another document's Field4

4) I continue and I make another loop and look for another document wich verify these conditions :

it should have the same Field1 just like the previous document and its Field6 equal to the previous document Field7 and its Field8 the same as Field8 in the first document

5) Then I take doc.Field4 and add it to the previous doc.Field4

使用 MyModel.findOne() 应该足以完成上面的任务 3、4 和 5。但是,由于调用的异步性质,您需要嵌套查询,但幸运的是嵌套调用的深度不超过 3,否则您会发现自己有一张通往回调 hell 的单程票。为了避免这些常见的陷阱,最好使用 Promises (因为默认情况下 native Mongoose 查询可以返回 Promise )或使用 node-async 包,其中包含许多用于处理此类情况的函数。

如果使用 async 库,它允许您高效地运行多个相互依赖的异步任务(如 MyModel.findOne() 调用),当它们全部完成时执行其他操作。在上面,您可以使用 async.series() 方法。


以下示例演示了上述概念,您可以在其中根据测试数据库中的以下示例文档计算 Qsi

填充测试数据库的 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" : "",
    }
])

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);                
            });
        }   
    });
});

示例输出:

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
}

关于node.js - 根据条件从现有字段计算分数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37791777/

有关node.js - 根据条件从现有字段计算分数的更多相关文章

  1. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  2. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  3. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  4. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  5. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  8. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

随机推荐