【问题标题】:Sails.js - Get an object (model) using multiple joinSails.js - 使用多重连接获取对象(模型)
【发布时间】:2014-11-21 14:20:02
【问题描述】:

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

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

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

所以我的数据库中有 3 个表:meta、lang 和 meta_lang。很简单,图胜于言,截图如下。

语言

元语言

我想要做的是在meta_table 中获取与'default' meta 和'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"}) 的内容。

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

【问题讨论】:

    标签: node.js sails.js


    【解决方案1】:

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

    在我看来,您似乎正在重写 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,瞧。
    您可以添加的另一个严格策略是在每个模型上设置“通过”和优势。您可以在关联文档中阅读更多相关信息,这取决于关联的性质(多对多等)

    在事先不知道 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 } ]
    

    【讨论】:

    • 感谢您的详细回答。我现在没有时间测试所有内容(今晚我会仔细看看)。只是一些cmets。 :) When I saw the mySQL code it seemed to me you are still thinking in MySQL and PHP which takes time to convert from => 对。 ^^" 但是我必须执行 SQL,因为我没有找到没有 SQL 的方法,我从 find()populate() 开始对我的对象没有成功。
    • 我看到您通过 meta_id 和 lang_id 获取 MetaLang 对象,那么通过 meta_code 和 lang_code 获取它们呢?我仍然不明白如何做到这一点,而不必 1/ 通过代码查找我的 Meta,2/ 通过代码查找我的语言,3/ 使用 id 查找我的 MetaLang。
    • 非常感谢您花时间回答这个问题。 :)
    • 它是一种异步语言和框架,您在第二个查询回调中查询 Lang 表并设置回调以查询 Meta 表您已经拥有两个 id,您查询第三个表,在第三个回调是您的将结果返回给客户
    • 这是一个非常有效的问题,不幸的是我不是这方面的专家,但我想它是 Node.js 与其他技术、异步与同步的基础。是的,它有 3 个查询,但由于 v8 和 Node.js,有 3 个非阻塞、超级快速的 io 读取。将其与需要 3 倍时间的表的 1 个阻塞进行比较。在 3 个快速查询之间,可能已经为另一个客户提供服务。这实际上取决于您的应用程序的性质,低需求的并发流量与高需求的单车道流量。
    【解决方案2】:

    你试过了吗:

    findCurrentTest: function (metaCode, langCode) {
        Meta.findByCode(metaCode).populate('metaLangs', {where: {code:langCode}}).exec(function(err, metaLang) {
            console.log('findCurrentTest');
            if (err) return console.log(err);
            console.log(metaLang);
        });
    },
    

    【讨论】:

    • 这仅返回'meta'表中的数据,'metaLang'为空。 [{metaLangs:[],code:'default',id:1}] 。我会在这个方向尝试其他的东西,谢谢!
    • 这个答案对我很有帮助。我以前没有意识到我可以查询“填充”方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多