草庐IT

node.js - MongoDB 聚合组最近 7 天的平均评分,值为空

coder 2023-11-02 原文

我正在尝试查询一个集合并检索过去 7 天(不包括当天)每一天的平均值。在某些或所有的日子里,可能没有平均值。

这是我目前所拥有的:

var dateTill = moment({hour:0,minute:0}).subtract(1, 'days')._d
var dateSevenDaysAgo = moment({hour:0,minute:0}).subtract(7, 'days')._d;

 Rating.aggregate([
   {
     $match:{
      userTo:facebookId,
      timestamp:{$gt:dateSevenDaysAgo,$lt:dateTill}
    }
},
{
  $group:{
    _id:{day:{'$dayOfMonth':'$timestamp'}},
    average:{$avg:'$rating'}
  }
},
{
  $sort:{
    '_id.day':1
  }
}
]

这给了我

[ { _id: { day: 20 }, average: 1 },
  { _id: { day: 22 }, average: 3 },
  { _id: { day: 24 }, average: 5 } ]

我想得到的是这样的:

[1,,3,,5,,]

按顺序表示最近 7 天的平均值,并且有一个空元素,表示当天没有平均值。

我可以尝试创建一个函数来检测差距在哪里,但是当平均值分布在两个不同的月份时,这将不起作用。例如 (July 28,29,30,31,Aug 1,2] - 八月的日子将被排序到我想要的数组的前面。

有更简单的方法吗?

谢谢!

最佳答案

人们经常询问“空结果”,而他们的想法通常来自他们如何使用 SQL 查询来解决问题。

但是,虽然为不包含分组键的项目抛出一组“空结果”是“可能的”,但这是一个困难的过程,很像人们使用的 SQL 方法,它只是将这些值抛入人为地声明,它确实不是一个非常受性能驱动的替代方案。考虑使用一组制造的 key “加入”。效率不高。

更聪明的方法是直接在客户端 API 中准备好这些结果,而不是发送到服务器。然后聚合输出可以与这些结果“合并”以创建一个完整的集合。

无论您想要存储要合并的集合取决于您,它只需要一个基本的“哈希表”和查找。但这是一个使用 nedb 的例子,它允许你保持 MongoDB 查询和更新的一套思路:

var async = require('async'),
    mongoose = require('mongoose'),
    DataStore = require('nedb'),
    Schema = mongoose.Schema,
    db = new DataStore();

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

var Test = mongoose.model(
  'Test',
  new Schema({},{ strict: false }),
  "testdata"
);

var testdata = [
  { "createDate": new Date("2015-07-20"), "value": 2 },
  { "createDate": new Date("2015-07-20"), "value": 4 },
  { "createDate": new Date("2015-07-22"), "value": 4 },
  { "createDate": new Date("2015-07-22"), "value": 6 },
  { "createDate": new Date("2015-07-24"), "value": 6 },
  { "createDate": new Date("2015-07-24"), "value": 8 }
];

var startDate = new Date("2015-07-20"),
    endDate = new Date("2015-07-27"),
    oneDay = 1000 * 60 * 60 * 24;

async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },
    function(callback) {
      async.each(testdata,function(data,callback) {
        Test.create(data,callback);
      },callback);
    },
    function(callback) {
      async.parallel(
        [
          function(callback) {
            var tempDate = new Date( startDate.valueOf() );
            async.whilst(
              function() {
                return tempDate.valueOf() <= endDate.valueOf();
              },
              function(callback) {
                var day = tempDate.getUTCDate();
                db.update(
                  { "day": day },
                  { "$inc": { "average": 0 } },
                  { "upsert": true },
                  function(err) {
                    tempDate = new Date(
                      tempDate.valueOf() + oneDay
                    );
                    callback(err);
                  }
                );
              },
              callback
            );
          },
          function(callback) {
            Test.aggregate(
              [
                { "$match": {
                  "createDate": {
                    "$gte": startDate,
                    "$lt": new Date( endDate.valueOf() + oneDay )
                  }
                }},
                { "$group": {
                  "_id": { "$dayOfMonth": "$createDate" },
                  "average": { "$avg": "$value" }
                }}
              ],
              function(err,results) {
                if (err) callback(err);
                async.each(results,function(result,callback) {
                  db.update(
                    { "day": result._id },
                    { "$inc": { "average": result.average } },
                    { "upsert": true },
                    callback
                  )
                },callback);
              }
            );
          }
        ],
        callback
      );
    }
  ],
  function(err) {
    if (err) throw err;
    db.find({},{ "_id": 0 }).sort({ "day": 1 }).exec(function(err,result) {
      console.log(result);
      mongoose.disconnect();
    });
  }
);

这给出了这个输出:

[ { day: 20, average: 3 },
  { day: 21, average: 0 },
  { day: 22, average: 5 },
  { day: 23, average: 0 },
  { day: 24, average: 7 },
  { day: 25, average: 0 },
  { day: 26, average: 0 },
  { day: 27, average: 0 } ]

简而言之,“数据存储”是使用 nedb 创建的,它的行为基本上与任何 MongoDB 集合相同(具有精简的功能)。然后,您可以为任何结果插入您的“键”范围内的预期值和默认值。

然后运行您的聚合语句,它只会返回查询集合中存在的键,您只需使用聚合值“更新”创建的具有相同键的数据存储。

为了提高效率,我在 parallel 中同时运行空结果“创建”和“聚合”操作, 利用 "upsert"功能和 $inc值的运算符。这些不会冲突,这意味着创建可以在聚合运行的同时发生,因此没有延迟。

这很容易集成到您的 API 中,因此您可以拥有所有您想要的键,包括那些在输出集合中没有数据聚合的键。

同样的方法适用于在您的 MongoDB 服务器上使用另一个实际集合来处理非常大的结果集。但是,如果它们非常大,那么无论如何您都应该预先聚合结果,并且只使用标准查询进行抽样。

关于node.js - MongoDB 聚合组最近 7 天的平均评分,值为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31661858/

有关node.js - MongoDB 聚合组最近 7 天的平均评分,值为空的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  2. ruby - 实现k最近邻需要哪些数据? - 2

    我目前有一个reddit克隆类型的网站。我正在尝试根据我的用户之前喜欢的帖子推荐帖子。看起来K最近邻或k均值是执行此操作的最佳方法。我似乎无法理解如何实际实现它。我看过一些数学公式(例如k表示维基百科页面),但它们对我来说并没有真正意义。有人可以推荐一些伪代码,或者可以查看的地方,以便我更好地了解如何执行此操作吗? 最佳答案 K最近邻(又名KNN)是一种分类算法。基本上,您采用包含N个项目的训练组并对它们进行分类。如何对它们进行分类完全取决于您的数据,以及您认为该数据的重要分类特征是什么。在您的示例中,这可能是帖子类别、谁发布了该项

  3. ruby-on-rails - Assets 管道损坏 : Not compiling on the fly css and js files - 2

    我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1

  4. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  5. node.js - 如何在 Travis CI 上的一个项目中运行 Node.js 和 Ruby 测试 - 2

    我有一个包含多个组件的存储库,其中大部分是用JavaScript(Node.js)编写的,一个是用Ruby(RubyonRails)编写的。我想要一个.travis.yml文件来触发一个运行每个组件的所有测试的构建。根据thisTravisCIGoogleGroupthread,目前还没有官方支持。我的目录结构是这样的:.├──构建服务器├──核心├──扩展├──网络应用├──流浪文件├──package.json├──.travis.yml└──生成文件我希望能够运行特定版本的Ruby(2.2.2)和Node.js(0.12.2)。我已经有了一个make目标,所以maketest在每

  6. ruby-on-rails - 获取最近发生的星期三? - 2

    如何使用Ruby(和Rails,如果有相关的辅助方法)获取最近发生的星期三?最终需要实际日期(5/1/2013)。 最佳答案 time=Time.nowdays_to_go_back=(time.wday+4)%7last_wed=days_to_go_back.days.ago 关于ruby-on-rails-获取最近发生的星期三?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions

  7. ruby-on-rails - ruby open ssl api for encrypted key (without nodes option) - 2

    在安装了openssllib的linux机器上,当您执行带有“-nodes”选项的“opensslpkcs12”时,您将获得带有未加密私钥的输出,但如果您跳过–nodes选项,则输出将具有加密的私钥。e.g.opensslpkcs12-intest.pfx-outtest.pem你应该看到像下面这样加密的私钥-----BEGINENCRYPTEDPRIVATEKEY-----MIIFDjBABgkqhkiGG7s=-----ENDENCRYPTEDPRIVATEKEY-----如何使用ruby​​的开放ssl库实现上述目标?这就是我用ruby​​生成私钥的方式:@private_key

  8. node.js - 从未编写过任何自动化测试,我应该如何开始行为驱动开发? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易

  9. ruby-on-rails - 将 Angular JS 与 Rails 集成 - 2

    我需要一些指导来了解如何将Angular整合到rails中。选择Rails的原因:我喜欢他们偏执的做事方式。还有迁移,gem真的很酷。使用angular的原因:我正在研究和寻找最适合SPA的框架。Backbone似乎太抽象了。我不得不在Angular和Ember之间做出选择。我首先开始阅读Angular,它对我来说很有意义。所以我从来没有去读过关于ember的文章。使用Angular和Rails的原因:我研究并尝试使用小型框架,例如grape、slim(是的,我也使用php)。但我觉得需要坚持项目的长期范围。我个人喜欢用Rails的方式做事。这就是我需要帮助的地方,我在Rails4中有

  10. ruby - 从谷歌开发者网站下载后,client_secret.json 为空 - 2

    我正在尝试从googleAPI下载client_secret.json。我正在执行https://developers.google.com/gmail/api/quickstart/ruby中列出的步骤.使用此向导在GoogleDevelopersConsole中创建或选择项目并自动启用API。在左侧边栏中,选择同意屏幕。选择电子邮件地址并输入产品名称(如果尚未设置),然后单击“保存”按钮。在左侧边栏中,选择凭据并点击创建新客户端ID。选择应用程序类型已安装应用程序,已安装应用程序类型为其他,然后单击“创建客户端ID”按钮。点击新客户端ID下的下载JSON按钮。将此文件移动到您的工作

随机推荐