我试图将RESToDB聚合用于RESTful api,但是遇到了以下情况。假设我有Subscriptions
模型,看起来像这样:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var SubscriptionSchema = new Schema({
// ...
cancelled: Date
});
如果订阅处于有效状态,则此cancelled
属性可以是undefined
,也可以是用户取消操作的Date
。
现在,我有一个路由GET /me/subscriptions
,它聚合订阅并有一个可选的查询参数:cancelled=true
(仅显示已取消)或cancelled=false
(仅显示有效)。如果未指定,则应返回任何订阅(活动或取消)。
var express = require('express'),
router = express.Router(),
Subscription = require('../../models/subscription');
router.get('/me/subscriptions', function(req, res, next) {
var cancelled = req.query.cancelled === 'true' ? { $exists: true } :
req.query.cancelled === 'false' ? { $exists: false } :
{ $exists: { $or: [ true, false ] } }; // wrong logic here
return Subscription.aggregate([
{ $match: { user: req.user._id, cancelled: cancelled }},
{ $project: {
// ...
}}
])
.exec()
// ...
});
module.exports = router;
如果我传递上面提到的查询参数,它将完美地工作,但如果未指定参数(或者它不等于true
或false
)则无法找到模型。我尝试了很多东西而不是错误的行(在$match
管道中):
cancelled: {}
cancelled: void 0
cancelled: { $exists: { $or: [ true, false ] } }
cancelled: { $exists: { $in: [ true, false ] } }
cancelled: { $exists: [ true, false ] } // obviously wrong, but hey
cancelled: null // obviously wrong, too
cancelled: { $or: [ { $exists: false }, { $exists: true } ] } // can't use $or here, but still, hey
现在看到的唯一解决方案就是这样,与不是undefined
而不是Date
类型的值进行比较,但它似乎太过于hacky。
cancelled: { $ne: 'some-impossible-value' }
非常感谢任何帮助。
答案 0 :(得分:2)
我认为稍微调整就能满足你想要的条件。
var express = require('express'),
router = express.Router(),
Subscription = require('../../models/subscription');
router.get('/me/subscriptions', function(req, res, next) {
var match_query = {user: req.user._id};
if (req.query.cancelled === 'true') {
match_query.cancelled = {$exists:true};
} else if(req.query.cancelled === 'false') {
match_query.cancelled = {$exists:false};
}
return Subscription.aggregate([
{ $match: match_query},
{ $project: {
// ...
}}
])
.exec()
// ...
});
module.exports = router;
你不需要添加{$ exists:{$或:[true,false]},如果你没有得到真或假,就不要添加任何东西来查询。
我没有检查代码是否存在语法错误,但从逻辑上讲它会起作用。
答案 1 :(得分:0)
我会重新构建 $match
管道,如下所示(需要安装momentjs库):
router.get('/me/subscriptions', function(req, res, next) {
var match = {
"$match": {
"user": req.user._id,
"cancelled": {}
}
};
if (req.query.cancelled === 'true' || req.query.cancelled === 'false') {
match["$match"]["cancelled"]["$exists"] = JSON.parse(req.query.cancelled);
} else if(moment(req.query.cancelled, moment.ISO_8601, true).isValid()){
match["$match"]["cancelled"] = moment(req.query.cancelled).toDate();
}
else {
match["$match"]["cancelled"]["$exists"] = false;
}
return Subscription.aggregate([match,
{ "$project": {
// ...
}}
]).exec()
// ...
});