node.js - Sails.js - 使用多重连接获取对象(模型)

标签 node.js sails.js

我是 node.js 的新手,也是 Sails.js 框架的新手。

我目前正在尝试使用我的数据库,我不了解 Sails.js 的所有内容,但我设法逐步完成我想做的事情。 (我习惯了一些PHP MVC框架,所以理解结构不是太难。)

在这里,我尝试使用 2 个 JOIN 子句从我的数据库中获取一行。我设法使用 SQLModel.query() 函数做到了这一点,但我想以一种“更干净”的方式做到这一点。

所以我的数据库中有 3 个表:meta、lang 和 meta_lang。非常简单,图胜于言,下面是一些屏幕截图。

meta table

语言

lang table

元语言

meta_lang table

我想要做的是在 meta_table 中获取与“default”元和“en”lang(例如)匹配的行。

这是 Meta 和 Lang 模型(我使用 sails generate model 命令创建它们并根据需要进行编辑):

module.exports = {
    attributes: {
        code : { type: 'string' },
        metaLangs:{
            collection: 'MetaLang',
            via: 'meta'
        }
    }
};

语言

module.exports = {
    attributes: {
        code : { type: 'string' },
        metaLangs:{
            collection: 'MetaLang',
            via: 'lang'
        }
    }
};

这是我的 MetaLang 模型,我创建了 3 个函数来测试多种方法。第一个函数 findCurrent 运行良好,但如您所见,我必须编写 SQL。如果可能的话,这是我想避免的,我发现它更干净(我想尽可能多地使用 Sails.js 工具)。

module.exports = {
    tableName: 'meta_lang',
    attributes: {
        title : { type: 'string' },
        description : { type: 'text' },
        keywords : { type: 'string' },
        meta:{
            model:'Meta',
            columnName: 'meta_id'
        },
        lang:{
            model:'Lang',
            columnName: 'lang_id'
        }
    },

    findCurrent: function (metaCode, langCode) {
        var query = 'SELECT ml.* FROM meta_lang ml INNER JOIN meta m ON m.id = ml.meta_id INNER JOIN lang l ON l.id = ml.lang_id WHERE m.code = ? AND l.code = ?';
        MetaLang.query(query, [metaCode, langCode], function(err, metaLang) {
            console.log('findCurrent');
            if (err) return console.log(err);
            console.log(metaLang);
            // OK this works exactly as I want (I would have prefered a 'findOne' result, only 1 object instead of an array with 1 object in it, but I can do with it.)
        });
    },

    findCurrentTest: function (metaCode, langCode) {
        Meta.findByCode(metaCode).populate('metaLangs').exec(function(err, metaLang) {
            console.log('findCurrentTest');
            if (err) return console.log(err);
            console.log(metaLang);
            // I get what I expected (though not what I want): my meta + all metaLangs related to meta with code "default".
            // What I want is to get ONE metaLang related to meta with code "default" AND lang with code "en".
        });
    },

    findCurrentOthertest: function (metaCode, langCode) {
        MetaLang.find().populate('meta', {where: {code:metaCode}}).populate('lang', {where: {code:langCode}}).exec(function(err, metaLang) {
            console.log('findCurrentOthertest');
            if (err) return console.log(err);
            console.log(metaLang);
            // Doesn't work as I wanted: it gets ALL the metaLang rows.
        });
    }
};

我还尝试先通过代码获取 Meta,然后通过代码获取 Lang,最后使用 Meta.id 和 Lang.id 获取 MetaLang。但是当我只能有一个查询时,我想避免 3 个查询。

我正在寻找的是 MetaLang.find({meta.code:"default", lang.code:"en"})

希望您已获得所有需要的详细信息,如果您没有,请发表评论并要求更多。

最佳答案

你知道populate是做什么用的吗?它用于在从数据库加载时包含整个关联对象。它实际上是您尝试执行的连接,如果您需要的只是行检索而不是在没有填充的情况下查询表将使您构建的两个函数都起作用。

在我看来,您似乎正在重写 Sails 如何进行关联。我建议再读一遍 Sails documentation: Associations 中的协会文档.根据您的情况,您只是尝试与每个表进行一对多关联,我猜您可以避免使用中间表,但要确定更好的 id 需要了解您的用例。

当我看到 mySQL 代码时,在我看来你仍然在考虑 MySQL 和 PHP,这需要时间来转换 :) 自己强制连接和中间表,为你自动重做很多事情。我在“磁盘”适配器上重做了你的例子,它工作得很好。除非绝对必要,否则 WaterlineORM 的全部要点是抽象下层到 SQL 的层。
这是我将为您的示例做的,首先没有 SQL,只是在磁盘适配器 ID 上创建模型:

  // Lang.js
  attributes: {
    id :{ type:  "Integer" , autoIncrement : true,  primaryKey: true },
    code :"string"
  }

你看到我在这里多余地做了什么吗?我并不真的需要 Id 部分,因为 Sails 为我做了。只是一个例子。

  // Meta.js
  attributes: {
    code :"string"
  }

更好 :) ?

 // MetaLang.js
attributes: 
 {
      title : "string",
      desc : "string",
      meta_id : 
      {
       model : "meta",
      },
     lang_id : 
     {
       model : "lang",    
     }
  }

现在,在简单地创建与您的示例相同的值之后,我运行 sails 控制台类型:

 MetaLang.find({meta_id : 1 ,lang_id:2}).exec(function(er,res){
  console.log(res);
 });

输出>>>

sails> [ { meta_id: 1,
    lang_id: 2,
    title: 'My blog',
    id: 2 } ]

现在如果你想显示什么是 id 1 的 meta 和什么是 id 2 的 lang,我们使用 populate,但是 join/search 的引用就这么简单。

sails> Meta_lang.find({meta_id : 1 ,lang_id:2}).populate('lang_id').populate('meta_id').exec(function(er,res){ console.log(res); });
undefined
sails> [ { 
  meta_id: 
     { code: 'default',
       id: 1 },
  lang_id: 
     { code: 'En',
       id: 2 },
    title: 'My blog',
    id: 2 } ]

此时,id 将适配器切换到 MySQL,然后创建具有与上述相同列名的 MySQL 表。创建 FK_constraints 瞧。
您可以添加的另一个strict 策略是在每个模型上设置“via”和支配。您可以在关联文档中阅读更多相关信息,这取决于关联的性质(多对多等)

在事先不知道 ID 的情况下获得相同的结果:

sails> Meta.findOne({code : "default"}).exec(function(err,needed_meta){
..... Lang.findOne({code : "En"}).exec(function(err_lang,needed_lang){
....... Meta_lang.find({meta_id : needed_meta.id , lang_id : needed_lang.id}).exec(function(err_all,result){
......... console.log(result);});
....... });
..... });
undefined
sails> [ { meta_id: 1,
    lang_id: 2,
    title: 'My blog',
    id: 2 } ]

关于node.js - Sails.js - 使用多重连接获取对象(模型),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27063460/

相关文章:

javascript - Node js Stripe 收到未知参数 : dob

javascript - 使用 TypeScript 和 Sails.js 会出现问题,TypeError : object is not a function

git - 部署 sails.js 应用程序的最佳方法是什么?

node.js - npm install 不在/usr/bin 安装东西

javascript - 在 sails js Node 框架中创建 url

javascript - Sails.js 水线 ORM 从乘法模型中删除数据

javascript - 上传文件 Angular.js FormData

node.js - Nodejs 中不支持的字符集 "ISO-8859-1"

javascript - Sequelize 在结果对象中混合了 Camel 大小写和蛇形大小写键

javascript - 扩展类在子方法和父方法之间移动