Nodejs mongoose问题,能否使用model的virtual属性作为查询条件?以及该例应该怎么查询?

Nodejs mongoose问题,能否使用model的virtual属性作为查询条件?以及该例应该怎么查询?

我使用了mongoose和moment模块 需要查询出occur_time end_time时间区间和 from to 时间区间有交集的RiskEvent, 其中end_time是model的virtual属性,根据两个属性计算出来的, 不知下面的查询对不对,运行查询不出结果, node新手,还不会调试。。。 另外怎么提高查询速度?这个索引该怎么建,我主要是根据** 给定的时间区间 bussiness ** 查询

** /model/risk_event.js **

var RiskEventSchema = new Schema({
    occur_time: {type: Date},
    duration_time: {type: Number},
    bussiness: {type: String},
    comment: {type: String}
});

RiskEventSchema.virtual(‘end_time’).get(function(){ return moment(this.occur_time).add(‘minutes’, this.duration_time); });

RiskEventSchema.index({occur_time: 1});

mongoose.model(‘RiskEvent’, RiskEventSchema);

** /proxy/risk_events.js **

exports.getRiskEventsByOccurTime = function(from, to, callback){
    RiskEvent.find({"$or": [{occur_time: {"$lte": moment(from, 'YYYY-MM-DD')},
            end_time: {"$gt": moment(from, 'YYYY-MM-DD')}},
        {occur_time: {"$lt": moment(to, 'YYYY-MM-DD').add('days',1)},
            end_time: {"$gt": moment(to, 'YYYY-MM-DD').add('days',1)}},
        {occur_time: {"$gte": moment(from, 'YYYY-MM-DD')},
            end_time: {"$lt": moment(to, 'YYYY-MM-DD').add('days',1)}}]}, callback);
};

2 回复

Nodejs Mongoose 问题:能否使用 model 的 virtual 属性作为查询条件?

在 Mongoose 中,virtual 属性并不是实际存储在数据库中的字段,因此不能直接用于查询。不过,你可以通过一些技巧来实现类似的功能。

示例代码及解释

首先,我们需要修改 RiskEvent 模型定义,并添加一个方法来处理查询逻辑。

修改模型定义

const mongoose = require('mongoose');
const moment = require('moment');

const Schema = mongoose.Schema;

// 定义 RiskEvent 模型
var RiskEventSchema = new Schema({
    occur_time: { type: Date },
    duration_time: { type: Number },
    bussiness: { type: String },
    comment: { type: String }
});

// 添加虚拟属性 end_time
RiskEventSchema.virtual('end_time').get(function() {
    return moment(this.occur_time).add('minutes', this.duration_time);
});

// 索引 occur_time 字段
RiskEventSchema.index({ occur_time: 1 });

// 导出模型
module.exports = mongoose.model('RiskEvent', RiskEventSchema);

修改查询逻辑

由于 virtual 属性不能直接用于查询,我们可以创建一个辅助函数来构建查询条件。

const RiskEvent = require('../models/risk_event');

exports.getRiskEventsByOccurTime = function(from, to, business, callback) {
    // 构建查询条件
    const query = {
        $and: [
            { occur_time: { $lte: moment(to) } },
            { end_time: { $gt: moment(from) } },
            { bussiness: business }
        ]
    };

    // 执行查询
    RiskEvent.find(query, callback);
};

解释

  1. Virtual 属性: end_time 是一个虚拟属性,它基于 occur_timeduration_time 计算得出。
  2. 查询条件: 在 getRiskEventsByOccurTime 函数中,我们构建了一个查询条件对象 query,确保 occur_time 小于等于 toend_time 大于 from,并且 bussiness 匹配给定的值。
  3. 执行查询: 使用 RiskEvent.find(query, callback) 来执行查询操作。

提高查询速度

为了提高查询速度,可以考虑为以下字段创建索引:

  • occur_time
  • end_time(虽然这是一个虚拟属性,但可以通过其他方式优化查询)

例如:

RiskEventSchema.index({ occur_time: 1 });
RiskEventSchema.index({ duration_time: 1 });

通过这些索引,查询操作将变得更加高效。


在 Mongoose 中,虚拟属性(Virtual Attributes)是无法直接用于数据库查询的。这是因为虚拟属性是在对象实例层面定义的,并没有存储在数据库中。但是,你可以通过中间件(如 prepost hooks)或者在查询前处理数据的方式来间接实现这一需求。

对于您的具体问题,由于 end_time 是一个虚拟属性,不能直接用作查询条件。解决方法之一是通过查询数据库中的实际字段来间接实现。例如,可以先查询满足部分条件的数据,然后在结果上进行过滤。

示例代码

首先,我们修改查询逻辑,只用 occur_timeduration_time 字段来进行查询,然后在获取到的结果上应用 end_time 的逻辑来过滤数据。

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const moment = require('moment');

// 定义模式
const RiskEventSchema = new Schema({
    occur_time: { type: Date },
    duration_time: { type: Number },
    bussiness: { type: String },
    comment: { type: String }
});

// 虚拟属性
RiskEventSchema.virtual('end_time').get(function () {
    return moment(this.occur_time).add('minutes', this.duration_time);
});

RiskEventSchema.index({ occur_time: 1 });

const RiskEvent = mongoose.model('RiskEvent', RiskEventSchema);

// 查询函数
exports.getRiskEventsByOccurTime = async (from, to, business) => {
    const fromMoment = moment(from, 'YYYY-MM-DD');
    const toMoment = moment(to, 'YYYY-MM-DD').add('days', 1);

    const riskEvents = await RiskEvent.find({
        occur_time: { $lte: toMoment.toDate() },
        bussiness: business
    }).exec();

    // 过滤出符合条件的事件
    const filteredRiskEvents = riskEvents.filter(event => {
        const eventEndTime = moment(event.occur_time).add('minutes', event.duration_time);
        return eventEndTime > fromMoment && eventEndTime <= toMoment;
    });

    return filteredRiskEvents;
};

解释

  1. 虚拟属性:定义了一个 end_time 的虚拟属性,基于 occur_timeduration_time 计算。
  2. 查询:使用 find 方法查询数据库,仅依据 occur_timebussiness 字段。
  3. 过滤:在得到的结果中进一步过滤出满足 end_time 条件的记录。

这种方式虽然绕过了直接使用虚拟属性,但依然能够实现您想要的功能。如果需要更高效的查询性能,考虑创建合适的索引或优化查询条件。

回到顶部