Search code examples
javascriptalgorithmdata-structuresinorderpreorder

convert inorder equation to preorder equation with mongoose query syntax


I have an javascript object as follows. please note the spaces in the string.

find = { search: "name:someName and ( place:someplace or place:someotherplace )" }

i want to convert the string to the following

query={ 
        $and: [  
                {name:'someName'} , 
                {$or: [
                       {place:'someplace'}, 
                       {place:'someotherplace'} 
                      ]
                }
              ]
      }

I would like generic code which works for any such AND, OR equations and converts them into respective mongoose queries. That is I want a inorder equation to be converted into preorder equation and then modified to get mongoose query.


Solution

  •  function formQuery(searchString) {
        let infixArray = convertStringtoInfix(searchString);
        if (bracketChecker(infixArray)) {
            let postFixArray = convertInfixToPostfix(infixArray);
            let finalQuery = convertPostfixToQuery(postFixArray);
            return finalQuery;
        } else {
            return 'bracket mismatch';
        }
    };
    
    function bracketChecker(searchArray) {
        let flag = true;
        let stack = [];
        searchArray.forEach((element) => {
            if (element == '(') {
                stack.push(element);
            }
            if (element == ')') {
                if (stack.length > 0) {
                    stack.pop();
                } else {
                    flag = false;
                }
            }
        });
        if (stack.length > 0) {
            flag = false;
        }
        return flag;
    }
    
    function convertPostfixToQuery(postFixArray) {
        let stack = [];
        postFixArray.forEach((element) => {
            if (typeof element == 'object') {
                //makes it regex ==========================================
                // Object.keys(element).forEach(function(key) {
                //  if (element[key] == 'true') {
                //      element[key] = true;
                //  } else if (element[key] == 'false') {
                //      element[key] = false;
                //  } else {
                //      element[key] = new RegExp(element[key], 'i');
                //  }
                // });
                //=========================================================
                stack.push(element);
            } else {
                let obj = {};
                let lastelement = stack.pop();
                let secondLastElement = stack.pop();
                obj[element] = [ lastelement, secondLastElement ];
                stack.push(obj);
            }
        });
        return stack[0];
        // return { and: /a/i };
    }
    
    function convertInfixToPostfix(infixArray) {
        let outputQueue = [];
        let operatorStack = [];
        infixArray.forEach((element) => {
            if (typeof element == 'object') {
                outputQueue.push(element);
            } else if (element == '(') {
                operatorStack.push(element);
            } else if (element == ')') {
                let paranMismatch = false;
                while (operatorStack.length > 0 && operatorStack[operatorStack.length - 1] != '(') {
                    outputQueue.push(operatorStack.pop());
                    if (operatorStack.length == 0) {
                        paranMismatch = true;
                        break;
                    }
                }
                if (paranMismatch) {
                    return 'mismatch';
                }
                if (operatorStack[operatorStack.length - 1] == '(') {
                    operatorStack.pop();
                }
            } else if (element == 'and' || element == 'or') {
                while (
                    operatorStack.length > 0 &&
                    operatorStack[operatorStack.length - 1] != '(' &&
                    operatorStack[operatorStack.length - 1].length >= element.length
                ) {
                    outputQueue.push(operatorStack.pop());
                }
                operatorStack.push(element);
            } else {
                return 'mismatch';
            }
        });
        operatorStack.reverse();
        operatorStack.forEach((element) => {
            if (element == '(') {
                return 'mismatch';
            } else {
                outputQueue.push(element);
            }
        });
        outputQueue = outputQueue.map((element) => {
            if (element == 'and' || element == 'or') return '$' + element;
            else return element;
        });
        return outputQueue;
    }
    
    function convertStringtoInfix(str) {
        let output = '';
        [ ...str ].forEach((c) => {
            if (c == '(' || c == ')') {
                output += ' ' + c + ' ';
            } else {
                output += c;
            }
        });
        output = output.split(' ');
        output = output.filter((ele) => ele != '');
        output = output.map((ele) => {
            if (ele.toLowerCase() == 'and' || ele.toLowerCase() == 'or') {
                return ele.toLowerCase();
            } else if (ele == '(' || ele == ')') {
                return ele;
            } else {
                let key = ele.split(':')[0];
                let value = ele.split(':')[1];
    
                let obj = {};
                obj[key] = value;
    
                return obj;
            }
        });
        return output;
    }
    let search = 'name:someName and ( place:someplace or place:someotherplace )'
    console.log(formQuery(search))
    

    and the output is:-

    {
            "$and": [
                {
                    "$or": [
                        {
                            "place": "someotherplace"
                        },
                        {
                            "place": "someplace"
                        }
                    ]
                },
                {
                    "name": "someName"
                }
            ]
        }