0

I want to query mongo for "unexpired or evergreen(posts with null expiration) posts created or bookmarked by me"

The problem with my query is that mongoose is combining the or statements together so that I'm incorrectly getting (unexpired or evergreen or mine or bookmarked) rather than ( (unexpired or evergreen) and (mine or bookmarked) )

How do I change the mongoose query to be the latter correct case I outlined above. Should I use an "and" clause... or perhaps I should just do a not(expiration > now) ?

var query =
      Invite.find({ isActive:true })
        .or([
          { 'expiration': {$gt: new Date()} },
          { 'expiration' : null }
        ])
        .or([
        { createdBy:userId },
        { 'bookmarked.id' : userId }
      ])
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
MonkeyBonkey
  • 46,433
  • 78
  • 254
  • 460

2 Answers2

3

You can put both of the $or clauses into a single $and by using the Query#and helper as:

var query =
  Invite.find({ isActive:true })
    .and([
      {$or: [
        { 'expiration': {$gt: new Date()} },
        { 'expiration': null }
      ]},
      {$or: [
        { 'createdBy': userId },
        { 'bookmarked.id' : userId }
      ]}
    ])
Christian P
  • 12,032
  • 6
  • 60
  • 71
JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
0

This is where I think "helper" methods are not really helping much because they are confusing the issue. JavaScript is a dynamically typed language so you don't need these helper methods to define the data structure which makes up the query. All the native operators to MongoDB are just accepted in the single query path:

Invite.find(
    {
        "isActive": true,
        "$and": [
            { "$or": [
                { "expiration": null },
                { "expiration": { "$gt": new Date() } }
            ]},
            { "$or": [
                { "createdBy": userId }
                { "bookmarked.id": userId }
            ]}
        ]
    },
    function(err,result) {

    }
);
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317