2016-10-13 12 views
1

私はMongoDB集約をRESTfulなapiに利用しようとしていますが、次の場合には固執しています。サブスクリプションがアクティブになっている、またはユーザーのキャンセルアクションのDateになった場合に、このcancelledプロパティは、undefinedのいずれかになります

var mongoose = require('mongoose'), 
    Schema = mongoose.Schema; 

var SubscriptionSchema = new Schema({ 
    // ... 
    cancelled: Date 
}); 

:私はこのようになりますSubscriptionsモデルを、持っている、と仮定します。

今、サブスクリプションを集約し、オプションのクエリパラメータcancelled=true(表示のみキャンセル)またはcancelled=false(表示のみ有効)を持つルートGET /me/subscriptionsがあります。指定されていない場合は、サブスクリプション(アクティブまたはキャンセル)を返します。

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 

唯一の解決策は、今見ているといないタイプDateundefinedない値と比較する、このようなものです、それはあまりにもハッキリと思われる。

cancelled: { $ne: 'some-impossible-value' } 

助けを非常に感謝します。

答えて

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; 

は{$が存在する:{$または:[真、偽]}、ちょうどあなたが真か偽取得しない場合、クエリには何も追加しないでください。

私は構文エラーのコードをチェックしていませんが、論理的には動作します。

+0

解決方法は間違いありませんが、簡潔にするために、「if-then-else」を避けるようにしました。ありがとう。 –

+0

私はあなたの答えを@chridamのものと組み合わせました: 'var match = {user:req.user._id}; (['true'、 'false'] .indexOf(req.query.cancelled)!== -1)match.cancelled = {$ exists:JSON.parse(req.query.cancelled)}; ' –

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() 
    // ... 
}); 
+0

ありがとうございました。しかし、ミリ秒単位の日付に基づいてサブスクリプションをクエリするのが有益なのかどうかは分かりません:Dあなたはドット構文を 'match $ match.cancelled。$ exist = true'のように使うことができます。 –