如何将Sequelize过滤器格式化为有效的JSON

时间:2018-01-26 16:18:38

标签: json node.js api sequelize.js

我正在设置API。服务器从客户端接收JSON形式的过滤器,以便在查询MySQL数据库时由sequelize使用。

我一直在和邮递员一起测试。

以下json可以发送到服务器,但是sequelize不喜欢"[Op.or]"因为它应该是[Op.or]而没有引号。

但是,如果我不添加引号,那么它是无效的JSON,我无法发布数据。

//Sequelize does not like this because of the quotes around "[Op.or]"
{
    "filters": {"week": 201740, "project": 8, "itemgroup": {"[Op.or]": ["group1", "group2"]}}
}

//This is can not be sent as a JSON body in an API request because there are
//no quotes around [Op.or]
{
    "filters": {"week": 201740, "project": 8, "itemgroup": {[Op.or]: ["group1", "group2"]}}
}

这是我的脚本文件,其中进行了sequelize调用。通过函数头中的filters变量传入JSON过滤器。

module.exports = {
    getAOLDataCount:  function (res, filters) {
        let result = '';
        wd = new WeeklyData(sequelize, Sequelize.DataTypes);
        wd.count({where: filters}).then(function (aolCount) {
            res.send('the value ' + aolCount);
        });
        return result;
    }
};

3 个答案:

答案 0 :(得分:1)

您的客户端(可能)不会安装Sequelize,也无法通过JSON传递Sequelize操作符,因此您尝试做的事情并非完全可能。您可能会让客户端发送字符串(例如orand,然后您必须将这些字符串映射到Sequelize运算符)[1]。

"filters": {"week": 201740, "project": 8, "itemgroup": {"or": ["group1", "group2"]}}

然后在您的服务器代码中,您需要维护一个字符串映射到Sequelize运算符:

const operatorsMap = {
  or: [Op.or],
  and: [Op.and],
  etc
}

然后,对于每个请求,您可以遍历所有键并使用Sequelize运算符替换字符串。

function isObject(o) {
  return o instanceof Object && o.constructor === Object;
}

function replacer(obj) {
  var newObj = {};
  for (key in obj) {
    var value = obj[key];

    if (isObject(value)) {
      newObj[key] = replacer(value);
    } else if (operatorsMap[key]) {
      var op = operatorsMap[key];
      newObj[op] = value;
    } else {
      newObj[key] = value
    }
  }

  return newObj;
}

module.exports = {
    getAOLDataCount:  function (res, filters) {
        let result = '';
        wd = new WeeklyData(sequelize, Sequelize.DataTypes);
        wd.count({where: replacer(filters)}).then(function (aolCount) {
            res.send('the value ' + aolCount);
        });
        return result;
    }
};

仅供参考,上述代码尚未经过测试。

[1]我不建议您了解项目的细节,我建议您重新考虑这种方法。客户端实际上不应该发送直接提供给ORM的JSON对象。糟糕的SQL注入怎么样?如果升级Sequelize并且旧过滤器被弃用怎么办?相反,考虑允许通过查询参数进行过滤,并让您的API基于此创建过滤器对象。

答案 1 :(得分:1)

这是运行mcranston18的答案的实现:

const Op = this.Sequelize.Op;
this.operatorsMap = { // Add additional operators as needed.
    $ne: Op.ne,
};
replaceOperators(oldObject) {
    let newObject = {};
    for (let key in oldObject) {
        let value = oldObject[key];

        if (typeof value === 'object') {
            newObject[key] = this.replaceOperators(value); // Recurse

        } else if (this.operatorsMap[key]) {
            let op = this.operatorsMap[key];
            newObject[op] = value;

        } else {
            newObject[key] = value;
        }
    }
    return newObject;
}

使用此代码,您可以执行以下操作:

let whereFilter = {"emailAddress":"xxx@xxx.org","id":{"$ne":7}};
let objectFilter = JSON.parse(whereFilter);
let translatedObjectFilter = this.replaceOperators(objectFilter);
let options = {};
options.where = translatedObjectFilter;
await this.table.findAll(options).then(....

通过获得转换字符串运算符以进行Sequelize调用的能力,苦苦挣扎的开发人员可以在客户端单页应用程序上完成更多工作,因为无需为每个不同的客户端查询编写带有文字对象的特定服务器端查询。服务器端框架可以是通用的,而不是特定于应用程序的。

例如,我正在构建的SPA具有仅5个js文件的服务器框架。客户端有28个js文件,并且还在不断增长。这使用了Sequelize 4.37.10。

答案 2 :(得分:0)

最后我从sequelize slack group中发现旧的运算符方法仍在代码库中。我不知道会留多久,但由于这是通过json发送的唯一方式,它可能会留下来。

所以它的工作方式是,不是使用[Op.or]而是使用$或。

示例:

"filters": {"week": 201740, "project": 8, "itemgroup": {"$or": ["group1", "group2"]}}