2014-11-21 4 views
5

Ich bin neu in node.js und neuer zu Sails.js Framework.Sails.js - Holen Sie ein Objekt (Modell) mit mehreren Join

Ich versuche gerade mit meiner Datenbank zu arbeiten, ich verstehe nicht alles mit Sails.js, aber ich schaffe es Schritt für Schritt was ich will. (ich einig PHP MVC-Frameworks verwendet werde, damit es nicht zu schwierig ist, die Struktur zu verstehen.)

Hier Ich versuche, eine Reihe von meiner Datenbank zu erhalten, unter Verwendung von 2 JOIN Klausel. Ich habe es geschafft, dies unter Verwendung der SQL und der Funktion zu tun, aber ich möchte dies auf eine "sauberere" Weise tun.

Also habe ich 3 Tabellen in meiner Datenbank: Meta, Lang und Meta_lang. Es ist ziemlich einfach und ein Bild ist besser als Worte, hier sind einige Screenshots.

meta

meta table

lang

lang table

meta_lang

meta_lang table

Was ich tun möchte, ist die Zeile in meta_table, die mit 'Standard' meta und 'en' lang (zum Beispiel) übereinstimmen.

Hier sind Meta und Lang-Modelle (Ich habe sie mit sails generate model Befehl und bearbeitet sie mit dem, was ich brauchte):

Meta

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

Lang

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

Und hier ist mein MetaLang-Modell mit 3 Funktionen, die ich erstellt habe, um sev zu testen verschiedene Methoden. Die erste Funktion, findCurrent, funktioniert einwandfrei, aber wie Sie sehen können, musste ich SQL schreiben. Das ist was ich vermeiden will, wenn es möglich ist, ich finde es sauberer (und ich möchte Sails.js Tools so oft wie möglich verwenden).

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

Ich habe auch versucht, durch Code meinen Meta zu bekommen zuerst, dann meine Lang von Code und metasprachl Meta.id und Lang.id verwenden. Aber ich möchte 3 Abfragen vermeiden, wenn ich nur eine haben kann.

Was ich suche würde etwas wie MetaLang.find({meta.code:"default", lang.code:"en"}) sein.

Hoffe, Sie haben alle benötigten Informationen, nur kommentieren und fragen Sie nach mehr, wenn Sie nicht tun.

Antwort

8

Wissen Sie, was für bevölkern ist?Es enthält das gesamte verknüpfte Objekt, wenn es von der Datenbank geladen wird. Es ist praktisch der Join, den Sie versuchen zu tun, wenn alles, was Sie brauchen, Zeilenabruf als das Abfragen der Tabelle ohne Auffüllen ist, macht beide Funktionen, die Sie gebaut haben, funktionieren.

Für mich sieht es so aus, als ob Sie neu schreiben, wie Sails die Assoziation gemacht hat. Id vorschlagen, den Associations docs einen weiteren Read in Sails documentation: Associations zu geben. Je nach Fall versuchen Sie nur eine Eins-zu-Viele-Verbindung mit jeder Tabelle, Sie könnten eine mittlere Tabelle vermeiden, aber um besser zu entscheiden, müssen Sie Ihren Anwendungsfall verstehen.

Als ich den mySQL-Code sah, dachte ich, dass Sie immer noch an MySQL und PHP denken, was Zeit braucht, um von :) zu konvertieren, indem Sie die Joins und Middle-Tabellen selbst erzwingen. Ich habe Ihr Beispiel auf 'Disk' Adapter erneuert und es hat perfekt funktioniert. Der ganze Sinn von WaterlineORM besteht darin, die Ebene des Herunterfahrens zu SQL zu abstrahieren, es sei denn, dies ist absolut notwendig. Hier
ist, was ich für Ihr Beispiel tun, zunächst ohne SQL nur auf einem Plattenadapter-ID, die Modelle erstellen:

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

Sie sehen, was ich redundant hier getan hat? Ich brauchte den Id Teil nicht wirklich, da Sails es für mich macht. Nur ein Beispiel.

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

besser :)?

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

Jetzt nach einfach die gleichen Werte wie Ihr Beispiel die Schaffung i laufen Segel Konsolentyp:

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

Ausgang >>>

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

Nun, wenn Sie anzeigen möchten, was meta Mit id 1 und was lang mit id 2 ist, verwenden wir populate, aber das Referenzieren für Join/Search ist genauso einfach.

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

An diesem Punkt id Schalter Adapter MySQL und dann die MySQL-Tabellen mit den gleichen Spaltennamen erstellen, wie oben. Erstellen Sie die FK_constraints und voila.
Eine weitere strenge Richtlinie, die Sie hinzufügen können, ist die 'Via' und Dominanz auf jedem Modell einzurichten. Sie können ohne zu wissen, die Ids vor Hand mehr über die in der Vereinigung Dokumentation und es hängt von der Art der Assoziation (many-to-many etc.)

Um das gleiche Ergebnis lesen:

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

Danke für diese detaillierte Antwort. Ich habe momentan keine Zeit, alles zu testen (ich werde heute Nacht genauer hinsehen). Nur ein paar Kommentare. :) 'Als ich den mySQL-Code sah, dachte ich, dass Sie immer noch in MySQL und PHP denken, was Zeit braucht, um von '=> richtig zu konvertieren. ^^ "Aber ich musste SQL machen, weil ich es ohne SQL nicht gefunden habe, ich habe mit' find() 'und' populate() 'auf meinen Objekten ohne Erfolg begonnen. –

+0

Ich sehe, dass Sie MetaLang bekommen object by meta_id und lang_id, wie wäre es mit meta_code und lang_code? Ich verstehe immer noch nicht wie ich es machen kann ohne 1/Finde meine Meta nach Code, 2/Finde meine Sprache nach Code, 3/Finde meine MetaLang mit IDs. –

+0

Vielen Dank, dass Sie sich die Zeit für diese Antwort genommen haben. :) –

1

Haben Sie versucht:

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

Dies gibt nur die Daten aus der 'Meta' Tabelle zurück, 'MetaLang' ist leer. '{{metaLangs: [], code: 'default', id: 1}]'. Ich werde andere Dinge in diese Richtung versuchen, danke! –

+0

Diese Antwort hilft mir wirklich. Ich wusste vorher nicht, dass ich eine Abfrage nach der "populate" Methode haben könnte. – JustWonder

Verwandte Themen