简体   繁体   中英

nodejs how to dynamically manipulate your MongoDB aggregate in your controller?

I have a very loooong aggregate in my nodejs controller:

agentSaleModel.aggregate([
    {
        $match: {
            $and: 
            [{ 
                _id: { $in: req.body.propertyID },
                active : true
            }]
        }
    }, etc....

And it works great when I got elements in my req.body.propertyID like ["property01","property02"] etc...

My problem is that I also want the aggregate to work when there are nothing in req.body.propertyID. (when its blank) - and then get all records.

This does not work:

agentSaleModel.aggregate([
    {
        $match: {
            $and: 
            [{ 
                _id: { $in: '' },
                active : true
            }]
        }
    }, etc....

So rather than doing an "if" with two huge sets of almost identical code:

if (req.body.propertyID) {
   ...the entire aggregate... 
} else {
   ...the entire aggregate minus the _id: { $in: req.body.propertyID },... 
}

Is there a smarter way to do this?

SOLUTION!! Thanks to FluffyNights :)

if (req.body.propertyID!='') {
    var matchStr = { 
        $match: {
            $and: 
            [{ 
                _id: { $in: req.body.propertyID },
                active : true
            }]
        }
    }
} else {
    var matchStr = { 
        $match: {
                active : true
        }
    }
}
agentSaleModel.aggregate([ matchStr, etc..... (rest of pipeline)

you could do it like this:

let query = [
    {
        $match: {
            $and: 
            [{ 
                active : true
            }]
        }
    }];
if(req.body.propertyID) {
   query[0]["$match"]["$and"][0]["_id"] = { $in: req.body.propertyID };
}
agentSaleModel.aggregate(query, ...)

you could also use regex, like:

if(!req.body.properyID){
    req.body.propertyID = [ ".*" ];
}
agentSaleModel.aggregate([
{
    $match: {
        $and: 
        [{ 
            _id: { $in: req.body.propertyID },
            active : true
        }]
    }
}, etc....

however, this might get slow. Im not sure if passing null to $in would work the way you want, you could try it though.

What about trying to construct query before running it.

For example.

var query = req.body.propertyID ? { $and: [{_id: { $in: req.body.propertyID }, active : true}]} : {active : true}

agentSaleModel.aggregate([
{
   $match: query
}, etc....

Hope this helps.

Here's an inline solution using computed property names :

$match: {
  $and: [
    {
      _id: { [ req.body.propertyID ? '$in' : '$exists' ] : req.body.propertyID || true },
      active: true,
    },
  ],
}

When req.body.propertyID exists, the query becomes:

_id : { $in : req.body.propertyID }

If not:

_id : { $exists : true }

EDIT : this will also allow req.body.propertyID to equal "ALL" if you explicitly want to match all documents:

let selectAll = ! req.body.propertyID || req.body.propertyID === 'ALL';
const query = {
  $match: {
    $and: [
      {
        _id: { [ selectAll ? '$exists' : '$in' ] : selectAll || req.body.propertyID },
        active: true,
      },
    ],
  },
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM