2

I am struggling to find a neater way to doing this. I can of course do it with classic if-else condition but would like to somehow delegate it to mongodb and use a single db call to achieve it. I am using node js and native mongo driver.

Basically I want to do a find query in mongo db ->

  1. Query will return one document based on search criteria (like using id)
  2. If found return document if not do a fallback
  3. If a match is NOT found, another document will be searched on a different criteria and returned instead.

Example -> Take following couple of documents

[{
 id: 1,
 status: 'current'
},
{
id: 2,
status: 'default'
}
]

So, in this case if query is done for status. If find is queried with status as current it will fetch document with id 1. If find is queried with status done, since it's not present as a fallback it should return default.

I guess I can leverage the use of aggregations to achieve this? How to do it I am stuck at that part. Also is it possible to achieve it without aggregation?

Any help would be appreciated. Thanks!!

twister
  • 53
  • 4

1 Answers1

2

Depending on how complicated your criteria is you can apply the following steps in a aggregation:

  1. Filter (to reduce data)
  2. Score Data
  3. Sort Data
  4. Limit to max result (1 in your case)

Filter

{
  "$match": {
    "$or": [
      {
        "status": "current"
      },
      {
        "status": "default"
      }
    ]
  }
}

Score

{
  "$project": {
    "id": 1,
    "status": 1,
    "score": {
      "$switch": {
        "branches": [
          {
            "case": {
              "$eq": ["$status", "current"]
            },
            "then": 1
          },
          {
            "case": {
              "$eq": ["$status", "default"]
            },
            "then": 0
          }
        ],
        "default": -1
      }
    }
  }
}

Be aware order in Switch Statements matters, especially if you have a lot of branches.

Evaluates a series of case expressions. When it finds an expression which evaluates to true, $switch executes a specified expression and breaks out of the control flow.

Sort

{
  "$sort": {
    "status": 1
  }
}

Limit

{
  "$limit": 1
}

Complete Pipeline

[
  {
    "$match": {
      "$or": [
        {
          "status": "current"
        },
        {
          "status": "default"
        }
      ]
    }
  },
  {
    "$project": {
      "id": 1,
      "status": 1,
      "score": {
        "$switch": {
          "branches": [
            {
              "case": {
                "$eq": ["$status", "current"]
              },
              "then": 1
            },
            {
              "case": {
                "$eq": ["$status", "default"]
              },
              "then": 0
            }
          ],
          "default": -1
        }
      }
    }
  },
  {
    "$sort": {
      "status": 1
    }
  },
  {
    "$limit": 1
  }
]

This is an easy to understand approach and easy extensible, but I don't know about the speed.

As reference: How to sort data in Mongo in a custom order

MisterMonk
  • 327
  • 1
  • 9