常规的mongodb的查找操作如下所示。本文提供一种自定义解析器的思路,自行定义mongodb的树形结构进行查找。
db.col.find(
{
$or: [
{key1: value1},
{key2: value2}
]
}
)
数据库中有如下数据
当你想要找一个叫做小C,且他的老板是sdsd的时候
是不是已经有点想吐了,老板是sdsd或者是qwer呢
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
但是查找语句写起来真的很崩溃啊喂。。
于是我脑洞大开,我们能不能自己写一套语法便于我们查找呢,如果我能够提供像如下这种查找语句,是不是看起来容易理解多了
( name=小C && ( owner=sdsd || owner=qwer ) )
是不是一下子就清爽了许多
基于此,我想到了用栈来操作,受启发于中缀表达式
代码实现如下
当然是你们最喜欢的爪洼
private static Map Parser(String string){
// String string="(name=张三 && (age=17 || age=18 || age=20) && sex=男)";
Stack<Map> stack=new Stack(); //stack中存放map
Stack operateStack=new Stack(); //operateStack记录运算符以及优先级
Stack tempOperator=new Stack();
string.split("=");
for(int i=0;i<string.length();i++)
{
switch (string.charAt(i)){
case '&':
operateStack.push("$and");
i++; //跳过第二个&
break;
case '|':
operateStack.push("$or");
i++; //跳过第二个|
break;
case '(':
operateStack.push("(");
break;
case '=': //把 name=张三 变成一个map放入栈stack中
HashMap map=new HashMap(); //构造Map对象,入栈 //这个等于号前 到 第一个 特殊符号后的 全都是key值
int k=i;
while(k>=0){ //不为特殊符号 && || (
k--;
if (string.charAt(k)=='(' || string.charAt(k)=='&' || string.charAt(k)=='|'){
break;
}
}
String key=string.substring(k+1,i); //key为 k到i之间的字符串了
k=i;
while(k<string.length()){ //同理。从k往后 到第一个特殊字符之间,都是value
k++;
if (string.charAt(k)==')' || string.charAt(k)=='&' || string.charAt(k)=='|'){
break;
}
}
String value=string.substring(i+1,k);
map.put(key,value);
stack.push(map);
break;
case ')': //此刻出栈 完成拼接
HashMap map1=new HashMap();
ArrayList list=new ArrayList(); // stack中取两个操作数,operaterStack中取一个运算符,拼接成$or/$and:[xx,xx],再压入栈中
String operator= (String) operateStack.pop();
if ("$or".equals(operator)) { //往前找到第一个左括号,记录经过的operator个数,这些元素全都是or关系
tempOperator.push("$or"); //认为括号内运算符都是平级的
String Nextoperator= (String) operateStack.pop();
int j=1;
while(!Nextoperator.equals("(")){
j++;
Nextoperator= (String) operateStack.pop();
} //说明这边有几个or 则从stack中运算几次
for(int times=0;times<=j;times++){
list.add(stack.pop());
}
map1.put("$or",list);
stack.push(map1);
break;
}
if("$and".equals(operator)){
tempOperator.push("$and"); //认为括号内运算符都是平级的
String Nextoperator= (String) operateStack.pop();
int j=1;
while(!Nextoperator.equals("(")){
j++;
Nextoperator= (String) operateStack.pop();
} //说明这边有几个and 则从stack中运算几次
for(int times=0;times<=j;times++){
list.add(stack.pop());
}
map1.put("$and",list);
stack.push(map1);
break;
}
}
}
return stack.pop();
}
最后返回这样的格式