[英]MongoDB aggregation: any value of $exists
I'm trying to leverage MongoDB aggregation for a RESTful api, but got stuck with the following case. 我正在尝试将MongoDB聚合用于RESTful api,但是遇到以下情况。 Suppose, I have
Subscriptions
model, which looks like this: 假设我有
Subscriptions
模型,如下所示:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var SubscriptionSchema = new Schema({
// ...
cancelled: Date
});
This cancelled
property can be either undefined
, if the subscription is active, or become a Date
of the user's cancel action. 如果订阅处于活动状态,则此
cancelled
属性可以是undefined
,也可以成为用户取消操作的Date
。
Now, I have a route GET /me/subscriptions
, which aggregates subscriptions and has an optional query parameter: cancelled=true
(show only cancelled) or cancelled=false
(show only active). 现在,我有一条路由
GET /me/subscriptions
,该路由聚合订阅并具有可选的查询参数: cancelled=true
(仅显示已取消)或cancelled=false
(仅显示活动)。 If not specified, should return any subscription (active or cancelled). 如果未指定,则应返回任何订阅(活动或已取消)。
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;
It works perfectly if I pass the above mentioned query parameter, but fails to find models if no parameter is specified (or if it is not equal to either true
or false
). 如果我传递上述查询参数,它会完美地工作,但是如果未指定参数(或者它不等于
true
或false
),则无法找到模型。 I have tried lots of stuff instead of the wrong line (in the $match
pipeline): 我尝试了很多东西而不是错误的行(在
$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
The only solution is see now is something like this, comparing against a value which is not undefined
and not of type Date
, but it seems way too hacky. 唯一的解决方案是现在看到类似这样的内容,将其与不是
undefined
且不是Date
类型的值进行比较,但似乎太过分了。
cancelled: { $ne: 'some-impossible-value' }
Any help is very much appreciated. 很感谢任何形式的帮助。
I think a little tweaking will satisfy the condition as you want. 我认为稍作调整即可满足您想要的条件。
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;
You don't need to add { $exists: { $or: [ true, false ] } , just don't add anything to query if you don't get true or false. 您不需要添加{$ exists:{$ or:[true,false]},如果您没有得到true或false,则无需添加任何查询内容。
I haven't checked code for syntax error, but logically it will work. 我没有检查代码中的语法错误,但是从逻辑上讲它可以工作。
I would restructure the $match
pipeline as follows (requires installing the momentjs library): 我将按如下方式重组
$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()
// ...
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.