Scene
Recently, there is a need to insert various types of data into the MongoDB, which is the database that records the business log.
Because the business object types are different, the data format of the insert is completely different.
In addition, you need to provide a query interface to search for data.
There is no problem inserting the data, but the query ...
Query Design Scheme
The first thought is to let users enter MongoDB query syntax, similar to JSON format. However, although the user is also developed, can not be familiar with this syntax, so give up.
The second idea is to have the user enter the SQL statement and then convert ... The result ended in failure.
Finally, I saw the interactive design of the ITunes Smart playlist:
Here, you can insert a condition, or you can insert a set of conditions (equivalent to inserting a bracket with many conditions in parentheses).
The expressions in the diagram can be considered: Score > 3 && type = "Music" && Author = "" && (Author = "" && Author = = "" && Author = "")
In other words, such an interaction can completely implement a variety of nested logic.
Data structure
In order to design such a structure, you must first think about the data structure.
After the analysis of the feeling, there are actually two types, one can be considered querygroup, one can be considered queryitem.
The code is as follows:
Copy Code code as follows:
public class Querygroup
{
Public GroupType GroupType {get; set;}
Public list<queryitem> the Items {get; set;}
Public list<querygroup> Groups {get; set;}
}
public class Queryitem
{
public string Name {get; set;}
Public Querysymbol Operatortype {get; set;}
public string Value {get; set;}
Public DataType valuetype {get; set;}
}
Querygroup contains a set of query criteria, a set of child querygroup, and an important attribute grouptype that represents the logical relationship of the set of data and OR. The "any" and "any" options in the above interface.
Queryitem Internal properties are field names, logical operation types (equal, not equal to, greater than ...). , and attribute types (integers, text ...). )。
After you design the data structure, there are several difficulties:
1. How to design the front-end interaction?
2. How to pass to the back end?
3. How do I convert to a query expression when I get the data from the backend?
Then the next one to conquer it!
Front-End design interaction
Here is the bootstrap, the interface is very good-looking!
First look at the front end design, the above is dynamic conditions, the following are some fixed conditions.
The structure here is consistent with the data structure above, and the HTML is divided into two categories, Querygroup and Queryitem.
In the two hidden Div, used as a template.
The code is as follows:
Copy Code code as follows:
<div style= "Display:none;" >
<div class= "Query-group-template" >
<div class= "Query-group OK" >
<div class= "Query-title" >
<span class= "Help-inline" > match the following </span>
<select class= "Input-small group-type" >
<option value= "1" > All </option>
<option value= "2" > any </option>
</select>
<span class= "Help-inline" > Rules:</span>
<button type= "button" class= "btn Btn-mini btn-success Add-query-item" title= "Add a condition" >
<i class= "Icon-plus icon-white" ></i>
</button>
<button type= "button" class= "btn Btn-mini btn-info Add-query-group" title= "add a set of conditions" >
<i class= "Icon-th-list icon-white" ></i>
</button>
<button type= "button" class= "btn Btn-mini btn-danger delete-query-group" title= "Delete this set of conditions" >
<i class= "Icon-minus icon-white" ></i>
</button>
</div>
</div>
</div>
<div class= "Query-item-template" >
<div class= "Query-item" >
<input type= "text" value= "placeholder=" field name "title=" field name class= "Property-name"/>
<select class= "Input-mini operate-type" title= "conditions" >
<option value= "1" >==</option>
<option value= "2" >!=</option>
<option value= "3" >></option>
<option value= "4" >>=</option>
<option value= "5" ><</option>
<option value= "6" ><=</option>
<option value= "7" >LK</option>
</select>
<input type= "text" class= "Query-value" value= "placeholder=" value "title=" value/>
<select class= "Input-medium value-type" >
<option value= "3" >String</option>
<option value= "1" >Int</option>
<option value= "2" >Double</option>
<option value= "4" >DateTime</option>
</select>
<button type= "button" class= "btn Btn-mini btn-danger delete-query-item" title= "delete Condition" >
<i class= "Icon-minus icon-white" ></i>
</button>
</div>
</div>
</div>
Here is not difficult, the most important place is actually the event of each button.
Take a closer look, a total of 4 buttons:
The above three are: add one line of conditions, add a set of conditions, delete this group of conditions.
The right one for a single condition is: delete this condition.
The logic here is actually very simple:
Copy Code code as follows:
$ (' #queryContainer '). Append ($ ('. Query-group-template>.query-group '). Clone ())
$ (' #queryContainer >.query-group '). A (). Find ('. Delete-query-group '). Remove ();
$ (' Button.add-query-item '). Live (' click ', function () {
$ (this). Parent (). Parent (). Append ($ ('. Query-item-template>.query-item '). Clone ());
return false;
});
$ (' Button.add-query-group '). Live (' click ', function () {
$ (this). Parent (). Parent (). Append ($ ('. Query-group-template>.query-group '). Clone ());
return false;
});
$ (' Button.delete-query-group '). Live (' click ', function () {
If!$ (this). Parent (). Parent (). Parent (). Hasclass (' Query-group ')) {return false;}
$ (this). Parent (). Parent (). remove ();
return false;
});
$ (' Button.delete-query-item '). Live (' click ', function () {
$ (this). Parent (). remove ();
return false;
});
In addition, look at the first two lines of the code, don't forget to add a set of criteria for the initial load, and remove the "delete this group condition" button from the default group.
Front-End data processing
Interface interaction is really simple, but how do you pass this data to the backend?
Take the form out of one field and pass it through? The back end is going to cry ... It's a total mess of data.
That... Since the structure of the query criteria is very clear, why not become a JavaScript object first?
Then, serialize this object ...
Then, pass the JSON to the back end ...
Finally, the backend defines the type of the same structure and then deserializes ...
In other words, in the process of interaction, you just need to instantiate the form data as an object in JavaScript!
Let me first define two objects (note that the field names must be the same as the back end):
Copy Code code as follows:
function Querygroup () {
This. GroupType = 0;
This. Items = [];
This. Groups = [];
}
function Queryitem () {
This. Name = ';
This. Operatortype = 0;
This. Value = ';
This. ValueType = 0;
}
The method of instantiating an object is also very simple and requires recursion, and the basic logic is:
Loop the inner object of the outermost querygroup once, and if it is queryitem, refer to the value, or call this method recursively if it is querygroup.
The code is as follows:
Copy Code code as follows:
function Getquerygroup (group) {
Group = $ (group);
var querygroup = new Querygroup ();
Querygroup.grouptype = parseint (Group.find ('. Group-type '). Val ());
var queryitems = Group.children ('. Query-item ');
for (var k = 0; k < queryitems.length; k++) {
var queryitem = new Queryitem ();
Queryitem.name = $ (queryitems[k]). Find ('. Property-name '). Val ();
Queryitem.operatortype = parseint ($ (queryitems[k)). Find ('. Operate-type '). Val ());
Queryitem.value = $ (queryitems[k]). Find ('. Query-value '). Val ();
Queryitem.valuetype = parseint ($ (queryitems[k)). Find ('. Value-type '). Val ());
QueryGroup.Items.push (Queryitem);
}
var childgroups = Group.children ('. Query-group ');
for (var k = 0; k < childgroups.length; k++) {
QueryGroup.Groups.push (Getquerygroup (childgroups[k));
}
return querygroup;
}
Finally, the form submission, which eventually generates an object, serializes the object into JSON and encodes it:
encodeURIComponent (Json.stringify (item))
Back-end data processing
Back-end data processing is mainly divided into two parts: deserialization, conversion to query conditions.
The data structure is defined above and can be deserialized directly as long as the field name is the same as in JSON.
Copy Code code as follows:
var json = uri.unescapedatastring (request["Query");
var item = jsonconvert.deserializeobject<querygroup> (JSON);
Two lines of code, it becomes an object in. net!
Finally, the generation of query conditions is also very simple, but also a method, recursive call can be, the basic logic and the previous paragraph of the process of instantiating the form data is very similar.
I have extended a method in Querygroup, in which Icriteria and imongoquery structure is similar, used MongoDB classmate when it is imongoquery can, it is only a layer, and eventually generate Imongoquery.
Copy Code code as follows:
public class Querygroup
{
Public GroupType GroupType {get; set;}
Public list<queryitem> the Items {get; set;}
Public list<querygroup> Groups {get; set;}
Public Icriteria Toicriteria ()
{
Icriteria result = null;
foreach (var criteria in geticriterialist ())
{
if (result = = null)
{
result = criteria;
Continue
}
if (GroupType = = Model.GroupType.AndAlse)
{
result = result. ADD (criteria);
Continue
}
if (GroupType = = Model.GroupType.OrElse)
{
result = result. or (criteria);
Continue
}
}
return result;
}
Private list<icriteria> geticriterialist ()
{
var list = new list<icriteria> ();
foreach (var item in Items)
{
List. ADD (new Criteria (item). Name, item. Operatortype, New QueryValue (item. ValueType, item. Value, Fieldhierarchylevel.child)));
}
foreach (var group in Groups)
{
List. ADD (group. Toicriteria ());
}
return list;
}
}
After you get the query criteria object, call the relevant query method directly.
Postscript
In this scenario, the MongoDB is used, so the final conversion is the MongoDB query object. In fact, it is also very convenient to convert SQL.
In addition, a little more complex, converted to the expression tree in. NET is also a problem with wood!
Finally attach a GIF Demo
Author: dozer