Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert JSON query conditions to MongoDB/Mongoose operations

I am building an application in Angular 8 on the client side and NodeJS 12 with MongoDB 4 / Mongoose 5 on the server side.

I have a query generated by the Angular query builder module in JSON format. The JSON object will be sent to the backend via a POST request.

Question: How can the JSON query be converted into MongoDB operators to perform the database query?

Here's an example of a simple query generated by the Query Builder plugin. Note the requirement for multiple levels of "nested" AND / OR conditions.

{
  "condition": "and",
  "rules": [
    {
      "field": "Brief_D_Reactiedatum",
      "operator": "!=",
      "value": "Eventtoets_Fn"
    },
    {
      "condition": "or",
      "rules": [
        {
          "field": "Alleen_AO",
          "operator": "=",
          "value": "Parkeerreden"
        }
      ]
    }
  ]
}
like image 983
pengz Avatar asked Jul 18 '19 17:07

pengz


1 Answers

You need to build MongoDB's $expr which is similar to the query that you're getting from Angular query builder module. Since the ruleSets can be nested you need to run your mapping function recursively. Below code probably doesn't cover every possible case but should give you a good introduction to get started with such mapping.

let q = {
  "condition": "and",
  "rules": [
    {
      "field": "Brief_D_Reactiedatum",
      "operator": "!=",
      "value": "Eventtoets_Fn"
    },
    {
      "condition": "or",
      "rules": [
        {
          "field": "Alleen_AO",
          "operator": "=",
          "value": "Parkeerreden"
        }
      ]
    }
  ]
};

const conditions = { "and": "$and", "or": "$or" };
const operators = { "=": "$eq", "!=": "$ne", "<": "$lt", "<=": "$lte", ">": "$gt", ">=": "$gte" };

const mapRule = rule => ({
    [operators[rule.operator]]: [ "$"+rule.field, rule.value ]
});

const mapRuleSet = ruleSet => {
    return {
        [conditions[ruleSet.condition]]: ruleSet.rules.map(
            rule => rule.operator ? mapRule(rule) : mapRuleSet(rule)
        )
    }
};

let mongoDbQuery = { $expr: mapRuleSet(q) };
console.log(mongoDbQuery);

Result expression can passed either to MongoDB's find method

db.col.find(mongoDbQuery);

or into $match pipeline stage:

db.col.aggregate([{ $match: mongoDbQuery }]);
like image 132
mickl Avatar answered Oct 13 '22 04:10

mickl