【问题标题】:Query to find by calculated date查询以按计算日期查找
【发布时间】:2015-09-07 08:54:26
【问题描述】:

我想在 mongoose 中创建一个查询来实现这个功能:

猫鼬模型:

Planted_crop: owner: id, date_planted: Date, crop: id, quantity: Number
Crop: name: String, water_consumption: Number, grow_time: Number (means hours)

现在我想获取所有尚未完全种植的作物,在半代码中就是这样:

if (plantedCrop.date_planted < plantedCrop.date_planted + plantedCrop.crop.grow_time) {
    // this crop should be selected
}

现在我需要把它翻译成 mongodb:

var PlantedCrop = mongoose.model("planted_crop");
PlantedCrop.find({ 
    date_planted: { 
        $lt: {
            date_planted + crop.grow_time * 3600
        }
    }
}).populate("crop").exec(function(err, crops) {
    // calculate water consumption
    var consumption = 0, planted;
    for (var i = 0; i < crops.length; i++) {
        planted = crops[i];
        consumption += planted.crop.water_consumption * planted.quantity;
    }
    console.log("Water consumption of planted crops is " + consumption + " liters.
});

我一直在创建这样的查询,有人可以帮助我吗?

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query


    【解决方案1】:

    您不应该这样做,因此答案的最佳部分将解释您为什么不想要这种方法。相反,您应该计算一个 grop 在创建时将增长的时间,这实际上只是维护一个额外的字段(仅显示必需的字段):

    var date = new Date();
    
    PlantedCrop.create({
        "owner": ownerId,
        "crop": cropId,
        "date"_planted": date,
        "grow_time": ( 1000 * 60 * 60 ) * 2, // "milliseconds" for two hours
        "ready_time": new Date( date.valueOf() + ( 1000 * 60 * 60 ) * 2)
    });
    

    然后从当前时间查找该作物当前是​​否“完全生长”很简单:

    PlantedCrop.find({ "ready_time": { "$gte": new Date() } },function(err,crops) {
    
    });
    

    如果您想要从当前日期起一小时“准备好”的东西,那么您只需这样做:

    PlantedCrop.find({ 
       "ready_time": { 
           "$gte": new Date( Date.now + ( 1000 * 60 * 60 ) )
       } 
    },function(err,crops) {
    
    });
    

    这在功能上很简单,不会令人困惑,因为所有信息在编写时都会记录下来,您只需查找它以设置它是否已经增长。

    在计算方面考虑这一点的“危险”是您开始使用 $where 类型的查询和 JavaScript 字段评估:

    PlantedCrop.find({
        "$where": function() {
            return this.date_planted.valueOf() + grow_time > Date.now;
        }
    },function(err,crops) {
    
    }); 
    

    这非常糟糕,因为这样的测试不能使用索引进行搜索,并且会“蛮力”尝试匹配集合中的每个文档。

    这是您想要避免的以及您想要在处理逻辑中保持清洁的内容,但另一种选择是在创建请求时在客户端上进行数学运算。只需向后工作并检查作物是在“不到一小时”前种植的,实际上生长时间更长:

    PlantedCrop.find({ 
       "date_planed": { 
           "$lte": new Date( Date.now - ( 1000 * 60 * 60 ) )
       },
       "grow_time": { "$gte": ( 1000 * 60 * 60 ) }
    },function(err,crops) {
    
    });
    

    这会在您要求的时间范围内找到所有“未完全生长”的作物。

    但至于原始点,它只是看起来笨拙和丑陋,只需存储最终计算的日期并单独查询即可解决。

    另外请确保所有这些数据都在一个集合中,就像一开始所建议的那样。您不能在称为“连接”的查询中引用填充项目的值,而 MongoDB 不这样做。人口只是通过执行另一个查询来“美化”对象引用以用整个对象替换这些对象引用,“在”完成初始查询之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-06
      • 1970-01-01
      • 2016-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-04
      相关资源
      最近更新 更多