如何在node.js中实现用户定义的规则?

时间:2014-02-23 07:43:33

标签: node.js mongodb drools rule-engine

user defined rule sample

我需要实现一个像上面那样的用户定义规则引擎(使用的技术:nodejs + mongodb)

我遇到了一个SO Q,它在MySQL中进行数据存储,但我不知道如何查询数据并通过javascript获取它:

What is an appropriate data structure and database schema to store logic rules?

关于设计的任何想法&实施得到高度赞赏。

阳光

2 个答案:

答案 0 :(得分:0)

使用您显示的规则构建SQL查询非常容易。构建mongo查询的情况不同。

我创建了一个类似的引擎,我将规则存储为sql规则,然后编写了一个模块来从sql查询构建mongo查询(一个简单的查询)。

为了将mongo规则与javascript对象相匹配,我使用了sift库(没有与mongo查询引擎相同的正则表达式支持) - https://github.com/crcn/sift.js

所以,如果可能的话,我建议你将数据存储在sql数据库中,然后在你完成正确的转义后应用你构造的sql规则(以避免sql注入)

这是我在前端用来构造sql类型规则的函数 -

rule这里是一个映射到UI中每一行的表达式数组)

function getRuleString(rule) {
    var andOrStack = [];
    var lastExpressionDepth = 0;
    var tempRuleString = '';
    var countOpenBrackets = 0;

    if(!rule || !rule.expressionRows) {
        return '';
    }

    rule.expressionRows.forEach(function(expressionRow, index) {
        expressionRow.depth = parseInt(expressionRow.depth, 10);
        if(lastExpressionDepth !== expressionRow.depth) {

            // if this is an outer expression than the previous
            if((lastExpressionDepth - expressionRow.depth) > 0) {
                for(var i=0; i<(lastExpressionDepth - expressionRow.depth); i++) {
                    tempRuleString += ' ) ';
                }
                tempRuleString += ' ' + andOrStack.pop() + ' ';
            } else {
                tempRuleString += ' ' + andOrStack.pop() + ' ( ';
            }

            lastExpressionDepth = expressionRow.depth;
        } else {
            if(index > 0) {
                tempRuleString += ' ' + andOrStack.pop() + ' ';
            }
        }

        tempRuleString += expressionRow.firstColumn + ' ' + expressionRow.operator + ' "' + expressionRow.expression + '"';
        andOrStack.push(expressionRow.andOr);
    });

    tempRuleString += Array.apply(null, Array(tempRuleString.split('(').length-tempRuleString.split(')').length)) // jshint ignore: line
            .map(String.prototype.valueOf, ' ) ').join('');

    return tempRuleString;
}

答案 1 :(得分:0)

这是一个简单的示例,说明了一个类似于您给出的示例的架构和MongoDB查询。为简单起见,我在mongo shell中写了这个; node.js版本将类似。希望这会让你知道如何开始。

首先,我们向订阅者集合添加一些文档:

db.subscriber.insert({
    date_added: ISODate('2014-01-01'),
    first_name: 'Fred',
    language: 'en'
})
db.subscriber.insert({
    date_added: ISODate('2014-01-10'),
    first_name: 'Jorge',
    language: 'es'
})
db.subscriber.insert({
    date_added: ISODate('2014-01-20'),
    first_name: 'Jimmy',
    language: 'en'
})
db.subscriber.insert({
    date_added: ISODate('2014-01-30'),
    first_name: 'Frodo',
    language: 'sjn'
})

这是一个类似于您给出的示例的查询,匹配满足基于日期范围,名字的子字符串匹配或该语言的完全匹配的任何条件的文档:

db.subscriber.find({
    $or: [
        {date_added: {$gte: ISODate('2014-01-30')}},
        {first_name: /Jim/},
        {language: 'es'}
    ]})

以下是该查询返回的文件:

{
    "_id" : ObjectId("530f6edc32292f1f130aae16"),
    "date_added" : ISODate("2014-01-10T00:00:00Z"),
    "first_name" : "Jorge",
    "language" : "es"
},
{
    "_id" : ObjectId("530f6edc32292f1f130aae17"),
    "date_added" : ISODate("2014-01-20T00:00:00Z"),
    "first_name" : "Jimmy",
    "language" : "en"
},
{
    "_id" : ObjectId("530f6edc32292f1f130aae18"),
    "date_added" : ISODate("2014-01-30T00:00:00Z"),
    "first_name" : "Frodo",
    "language" : "sjn"
}

这有助于您入门吗?