MongoDB聚合:$存在的任何值
我试图利用MongoDB聚合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
),则无法find模型。 我已经尝试了很多东西,而不是错误的行(在$match
pipe道中):
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
而不是typesDate
,但它似乎太hacky。
cancelled: { $ne: 'some-impossible-value' }
很感谢任何forms的帮助。
我认为只要稍微调整就可以满足条件。
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]},只要不添加任何东西来查询,如果你没有得到真或假。
我没有检查代码的语法错误,但逻辑上它会工作。
我将重构$match
pipe道,如下所示(需要安装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() // ... });