mongoose条件查询 – 类似声明的情况

我想创build一个查询,将返回给定年份的收入集合。 我的模式是这样的:

export const IncomeSchema = new mongoose.Schema({ name: { type: String, required: true }, amount: { type: Number, required: true }, amountAfterTax: { type: Number, required: false }, dateFrom: { month: Number, year: Number }, dateTo: { month: Number, year: Number }, isMonthly: { type: Boolean, required: true }, userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } }, { toJSON: { virtuals: true } }); // somehow use the req.params.year return DB.Incomes.find({ userId: req.user ).exec().then(incomes => { let incomesForMonth = incomes.filter(income => !income.isMonthly ? (income.dateFrom.year== req.params.year) : (income.dateFrom.year <= req.params.year && income.dateTo.year >= req.params.year) }); 

问题是,我想要查询运行的方式: – 如果收入是每年,那么年份必须是相等的dateFrom.year – 如果收入!isMonthly那么年份必须在dateFrom.year和dateTo.year之间

直到现在,我从数据库返回一切,并在内存中处理它们,这不是一个最好的解决scheme。 在SQL Server中,我将使用CASE WHEN语句。 我可以用什么mongoose?

不幸的是,对于你当前的版本,我不能想到任何具有模仿case语句/expression式的本地MongoDB操作符的执行解决scheme。

但是,对于MongoDB Server 3.4和mongoose> = 4.7.3,有一个解决scheme,您可以使用聚合框架,特别是新的$addFields阶段和$switch运算符进行此类查询。

$addFields阶段相当于$project阶段,它明确指定input文档中的所有现有字段,并向文档添加新字段。 在你的情况下,你需要它来创build一个新的字段字段,包含filter逻辑,然后用于$match查询。

$switch操作符评估一系列的caseexpression式。 当它find一个expression式的值为true时, $switch执行一个指定的expression式,并跳出控制stream。

我们用一个mongo shell例子来演示这个:

填充testing集合:

 db.test.insert([ { name: "foo", amount: 4, amountAfterTax: 3.2, dateFrom: { month: 11, year: 2016 }, dateTo: { month: 2, year: 2017 }, isMonthly: true, userId: ObjectId("5864b49ab5a589b63ee298e8") }, { name: "test", amount: 547.74, amountAfterTax: 507.15, dateFrom: { month: 4, year: 2016 }, dateTo: { month: 4, year: 2017 }, isMonthly: true, userId: ObjectId("5864b49ab5a589b63ee298e8") }, { name: "bar", amount: 56, amountAfterTax: 47.54, dateFrom: { month: 5, year: 2016 }, dateTo: { month: 7, year: 2016 }, isMonthly: false, userId: ObjectId("5864b49ab5a589b63ee298e8") } ]) 

运行聚合查询

 year = 2016; db.test.aggregate([ { "$addFields": { "incomesForMonth": { "$switch": { "branches": [ { "case": "$isMonthly", /* same as "case": { "$eq": [ "$isMonthly", true ] }, */ "then": { "$eq": [ "$dateFrom.year", year ] } }, { "case": { "$eq": [ "$isMonthly", false ] }, "then": { "$and": [ { "$lte": [ "$dateFrom.year", year ] }, { "$gte": [ "$dateTo.year", year ] } ] } } ] } } } }, { "$match": { "incomesForMonth": true } } ]) 

示例输出

 /* 1 */ { "_id" : ObjectId("586ea7bafedfbcfd0ed15f9a"), "name" : "foo", "amount" : 4.0, "amountAfterTax" : 3.2, "dateFrom" : { "month" : 11.0, "year" : 2016.0 }, "dateTo" : { "month" : 2.0, "year" : 2017.0 }, "isMonthly" : true, "userId" : ObjectId("5864b49ab5a589b63ee298e8"), "incomesForMonth" : true } /* 2 */ { "_id" : ObjectId("586ea7bafedfbcfd0ed15f9b"), "name" : "test", "amount" : 547.74, "amountAfterTax" : 507.15, "dateFrom" : { "month" : 4.0, "year" : 2016.0 }, "dateTo" : { "month" : 4.0, "year" : 2017.0 }, "isMonthly" : true, "userId" : ObjectId("5864b49ab5a589b63ee298e8"), "incomesForMonth" : true } /* 3 */ { "_id" : ObjectId("586ea7bafedfbcfd0ed15f9c"), "name" : "bar", "amount" : 56.0, "amountAfterTax" : 47.54, "dateFrom" : { "month" : 5.0, "year" : 2016.0 }, "dateTo" : { "month" : 7.0, "year" : 2016.0 }, "isMonthly" : false, "userId" : ObjectId("5864b49ab5a589b63ee298e8"), "incomesForMonth" : true }