简体   繁体   English

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

[英]Sails.js - Get an object (model) using multiple join

I am new to node.js and newer to Sails.js framework. 我是node.js的新手,也是Sails.js框架的新手。

I am currently trying to work with my database, I don't understand all the things with Sails.js but I manage to do what I want step by step. 我目前正在尝试使用我的数据库,我不了解Sails.js的所有内容,但我设法按照我想要的步骤进行操作。 (I am used to some PHP MVC frameworks so it is not too difficult to understand the structure.) (我习惯了一些PHP MVC框架,因此理解结构并不太难。)

Here I am trying to get a row from my database, using 2 JOIN clause. 在这里,我试图从我的数据库中获取一行,使用2 JOIN子句。 I managed to do this using SQL and the Model.query() function, but I would like to do this in a "cleaner" way. 我设法使用SQLModel.query()函数执行此操作,但我想以“更清洁”的方式执行此操作。

So I have 3 tables in my database: meta, lang and meta_lang. 所以我的数据库中有3个表:meta,lang和meta_lang。 It's quite simple and a picture being better than words, here are some screenshots. 它非常简单,图片比文字好,这里有一些截图。

meta

元表

lang

郎表

meta_lang meta_lang

meta_lang表

What I want to do is to get the row in meta_table that match with 'default' meta and 'en' lang (for example). 我想要做的是让meta_table中的行与' meta_table和' meta_table匹配(例如)。

Here are Meta and Lang models (I created them with sails generate model command and edited them with what I needed): 这是Meta和Lang模型(我使用sails generate model命令创建它们并使用我需要的内容编辑它们):

Meta

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

Lang

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

And here is my MetaLang model, with 3 functions I created to test several methods. 这是我的MetaLang模型,我创建了3个函数来测试几种方法。 The first function, findCurrent , works perfectly, but as you can see I had to write SQL. 第一个函数findCurrent工作得很好,但正如你所看到的,我必须编写SQL。 That is what I want to avoid if it is possible, I find it more clean (and I would like to use Sails.js tools as often as I can). 这是我想要避免的,如果可能的话,我发现它更干净(我想尽可能多地使用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.
        });
    }
};

I also tried to first get my Meta by code, then my Lang by code, and MetaLang using Meta.id and Lang.id . 我还尝试先使用代码获取Meta,然后使用Meta.id和Lang.id获取我的Lang代码和MetaLang。 But I would like to avoid 3 queries when I can have only one. 但是当我只有一个查询时,我想避免3个查询。

What I'm looking for would be something like MetaLang.find({meta.code:"default", lang.code:"en"}) . 我正在寻找的东西就像MetaLang.find({meta.code:"default", lang.code:"en"})

Hope you've got all needed details, just comment and ask for more if you don't. 希望你得到所有需要的细节,只需评论,如果你不这样做就要求更多。

Do you know what populate is for ? 你知道populate是为了什么吗? its for including the whole associated object when loading it from the database. 它用于在从数据库加载时包含整个关联对象。 Its practically the join you are trying to do, if all you need is row retrieval than quering the table without populate will make both functions you built work. 它实际上是你想要做的连接,如果你需要的只是行检索而不是在没有填充的情况下查询表将使你构建的两个函数都工作。

To me it looks like you are re-writing how Sails did the association. 对我来说,看起来你正在重写Sails如何进行协会。 Id suggest giving the Associations docs another read in Sails documentation: Associations . 我建议在Sails文档中另外阅读Associations文档:关联 As depending on your case you are just trying a one-to-many association with each table, you could avoid a middle table in my guess, but to decide better id need to understand your use-case. 根据您的情况,您只是尝试与每个表进行一对多关联,您可以避免使用中间表,但要确定更好的ID需要了解您的用例。

When I saw the mySQL code it seemed to me you are still thinking in MySQL and PHP which takes time to convert from :) forcing the joins and middle tables yourself, redoing a lot of the stuff sails automated for you. 当我看到mySQL代码时,在我看来你仍然在思考MySQL和PHP需要时间来转换:)自己强制连接和中间表,为你自动重做很多东西。 I redone your example on 'disk' adapter and it worked perfectly. 我在'磁盘'适配器上重做你的例子,它工作得很好。 The whole point of WaterlineORM is to abstract the layer of going down to SQL unless absolutely necessary. 除非绝对必要,否则WaterlineORM的重点是将下层的层抽象为SQL。
Here is what I would do for your example, first without SQL just on a disk adapter id create the models : 以下是我将为您的示例所做的事情,首先在没有SQL的情况下,只需在磁盘适配器上创建模型:

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

you see what i did redundantly here ? 你看到我在这里多余的做了什么? I did not really need the Id part as Sails does it for me. 我并不真正需要Id部分,因为Sails为我做了。 Just an example. 只是一个例子。

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

better :) ? 更好:)?

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

Now after simply creating the same values as your example i run sails console type : 现在,在简单地创建与您的示例相同的值之后,我运行sails控制台类型:

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

Output >>> 输出>>>

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

Now if you want to display what is meta with id 1 and what is lang with id 2, we use populate, but the referencing for join/search is just as simple as this. 现在,如果你想显示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 } ]

At this point, id switch adapters to MySQL and then create the MySQL tables with the same column names as above. 此时,id切换适配器到MySQL, 然后使用与上面相同的列名创建MySQL表。 Create the FK_constraints and voila. 创建FK_constraints和瞧。
Another strict policy you can add is to set up the 'via' and dominance on each model. 您可以添加的另一个严格的策略是在每个模型上设置“通过”和优势。 you can read more about that in the Association documentation and it depends on the nature of association (many-to-many etc.) 您可以在协会文档中阅读更多相关信息,这取决于关联的性质(多对多等)

To get the same result without knowing the Ids before-hand : 要在不事先了解Ids的情况下获得相同的结果:

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 } ]

Have you tried: 你有没有尝试过:

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);
    });
},

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM