Home > database >  Mongodb aggregate (problem with $and - $expr)
Mongodb aggregate (problem with $and - $expr)

Time:10-22

I have a problem with mongodb

const getBookingStatus = (status) => {
  if (!status) return {};
  const qStatus = {};
  if (status === 'progress') qStatus.$and = [{ $ne: statusList.declined }, { $lt: statusList.confirmed }];
  if (status === 'confirmed') qStatus.$and = [{ $gt: statusList.signed }, { $lt: statusList.completed }];
  if (status === 'done') qStatus.$gte = statusList.completed;
  return { status: { ...qStatus } };
};

When I call const query = ...getBookingStatus(status), and use it in a $match it works for the status === 'done' but doesn't for the others. I have this error : "message": "unknown operator: $and". I've tried to add $expr like : if (status === 'progress') qStatus.$expr = { $and: [{ $ne: statusList.declined }, { $lt: statusList.confirmed }] }; but it doesn't work neither. Please help me

CodePudding user response:

The problem has to do with how the top level status field factors into the the comparisons that get nested inside of the $and. When using $and, each entry is an expression that must reference a field. So right now what gets generated is something like:

{
  status:  {
    $and: [
      { $ne: <Val1> }, 
      { $lt: <Val2> }
    ] 
  }
}

If you remove the $and and the array wrappers, and just provide the two filters as a single object, you will generate something like this instead:

{
  status:  {
    $ne: <Val1>, 
    $lt: <Val2>
  }
}

This more closely matches what your 'done' situation generates and successfully uses:

{
  status:  {
    $gte: <Val1>
  }
}

Here is a basic playground demonstration.

So the solution is probably to change

  if (status === 'progress') qStatus.$and = [{ $ne: statusList.declined }, { $lt: statusList.confirmed }];
  if (status === 'confirmed') qStatus.$and = [{ $gt: statusList.signed }, { $lt: statusList.completed }];

To something like:

  if (status === 'progress') qStatus = { $ne: statusList.declined, $lt: statusList.confirmed };
  if (status === 'confirmed') qStatus = { $gt: statusList.signed, $lt: statusList.completed };
  • Related