素晴らしいコミュニティモジュール

fibjs のオブジェクト リレーショナル マッピング

ビルドステータス

インストール

1
npm install fib-orm

テスト

1
npm run ci

DBMSのサポート

  • MySQL と MariaDB
  • SQLite

特徴

fib-orm は、node-orm オブジェクトに一連の同期バージョン メソッドを追加します。

前書き

これは fibjs オブジェクトのリレーショナル マッピング モジュールです。

例:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
var orm = require("fib-orm"); var db = orm.connectSync("mysql://username:password@host/database"); var Person = db.define("person", { name : String, surname : String, age : Number, // FLOAT male : Boolean, continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type photo : Buffer, // BLOB/BINARY data : Object // JSON encoded }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } }, validations: { age: orm.enforce.ranges.number(18, undefined, "under-age") } }); // add the table to the database db.syncSync(); // add a row to the person table Person.createSync({ id: 1, name: "John", surname: "Doe", age: 27 }); // query the person table by surname var people = Person.findSync({ surname: "Doe" }); // SQL: "SELECT * FROM person WHERE surname = 'Doe'" console.log("People found: %d", people.length); console.log("First person: %s, age %d", people[0].fullName(), people[0].age); people[0].age = 16; people[0].saveSync();

次のような node.js バージョン:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
var orm = require("orm"); orm.connect("mysql://username:password@host/database", function (err, db) { if (err) throw err; var Person = db.define("person", { name : String, surname : String, age : Number, // FLOAT male : Boolean, continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type photo : Buffer, // BLOB/BINARY data : Object // JSON encoded }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } }, validations: { age: orm.enforce.ranges.number(18, undefined, "under-age") } }); // add the table to the database db.sync(function(err) { if (err) throw err; // add a row to the person table Person.create({ id: 1, name: "John", surname: "Doe", age: 27 }, function(err) { if (err) throw err; // query the person table by surname Person.find({ surname: "Doe" }, function (err, people) { // SQL: "SELECT * FROM person WHERE surname = 'Doe'" if (err) throw err; console.log("People found: %d", people.length); console.log("First person: %s, age %d", people[0].fullName(), people[0].age); people[0].age = 16; people[0].save(function (err) { // err.msg = "under-age"; }); }); }); }); });

ドキュメンテーション

Fibjs は新しい関数を追加せず、ドキュメントの開発は node-orm を参照でき、非同期呼び出しを同期バージョンwikiに変更するだけで済み ます

設定

wiki の情報を参照してください

接続中

wiki の情報を参照してください

モデル

モデルは、1 つまたは複数のデータベース テーブルの抽象化です。モデルは関連付けをサポートします (詳細は後述)。モデルの名前は、テーブル名と一致すると見なされます。

モデルは、テーブル データにアクセスして操作するための動作をサポートします。

モデルの定義

wiki の情報を参照してください

Properties

wiki の情報を参照してください

Instance Methods

モデル定義中に渡されます。

1 2 3 4 5 6 7 8 9 10 11 12 13
var Person = db.define('person', { name : String, surname : String }, { methods: { fullName: function () { return this.name + ' ' + this.surname; } } }); var person = Person.getSync(4); console.log( person.fullName() );

Model Methods

モデルで直接定義されます。

1 2 3 4 5 6 7 8 9
var Person = db.define('person', { name : String, height : { type: 'integer' } }); Person.tallerThan = function(height) { return this.findSync({ height: orm.gt(height) }); }; var tallPeople = Person.tallerThan( 192);

モデルの読み込み [サポート対象外]

モデルは個別のモジュールにすることができます. モデルを保持するモジュールが module.exports を使用してデータベース接続を受け入れる関数を公開していることを確認してから、好きなようにモデルをロードしてください。

注 - このテクニックを使用すると、負荷を連鎖させることができます。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// your main file (after connecting) db.loadSync("./models"); // loaded! var Person = db.models.person; var Pet = db.models.pet; // models.js module.exports = function (db) { db.loadSync("./models-extra"); db.define('person', { name : String }); }; // models-extra.js module.exports = function (db) { db.define('pet', { name : String }); };

モデルの同期

wiki の情報を参照してください

モデルの削除

wiki の情報を参照してください

高度なオプション

ORM2 では、モデル定義にいくつかの高度な調整を行うことができます。これらは、設定を介して、またはdefineモデルをセットアップするの呼び出しで構成できます

たとえば、各モデル インスタンスにはデータベース内で一意の ID があります。このテーブル列は自動的に追加され、デフォルトで「id」と呼ばれます。
独自のkey: trueを定義し場合、「id」は追加されません。

1 2 3 4 5 6 7 8 9 10 11 12
var Person = db.define("person", { personId : { type: 'serial', key: true }, name : String }); // You can also change the default "id" property name globally: db.settings.set("properties.primary_key", "UID"); // ..and then define your Models var Pet = db.define("pet", { name : String });

ペットモデルには、anUIDと a の2 つの列がありますname

複合キーを持つこともできます:

1 2 3 4
var Person = db.define("person", { firstname : { type: 'text', key: true }, lastname : { type: 'text', key: true } });

別のオプション:

  • identityCache : (デフォルト:) ID キャッシュ (シングルトン)を有効falsetrueするように設定するか、タイムアウト値 (秒単位) を設定します。
  • autoSave : (デフォルト:)プロパティを変更した直後にインスタンスを保存するfalseようtrue設定します。
  • autoFetch : (デフォルト:) データベースからインスタンスを取得するときに関連付けを取得するfalseようtrue設定します。
  • autoFetchLimit: (デフォルト:) 有効になっている1場合autoFetch、これは自動的に取得するフープ (関連付けの関連付け) の数を定義します。

フック

wiki の情報を参照してください

アイテムを見つけます

Model.getSync(id, [ options ])

データベースから特定の要素を取得するには、 を使用しますModel.get

1 2
var person = Person.getSync(123); // finds person with id = 123

Model.findSync([ conditions ] [, options ] [, limit ] [, order ])

1 つまたは複数の要素を見つけるには、より多くのオプションがあり、各要素は特定のパラメーターの順序で指定できます. (空のオブジェクトであっても)optionsconditionsでなければなりません

1 2
var people = Person.findSync({ name: "John", surname: "Doe" }, 3); // finds people with name='John' AND surname='Doe' and returns the first 3

制限している、または単に並べ替えたいという理由で結果を並べ替える必要がある場合は、次のようにします。

1 2 3 4 5 6
var people = Person.findSync({ surname: "Doe" }, "name"); // finds people with surname='Doe' and returns sorted by name ascending people = Person.findSync({ surname: "Doe" }, [ "name", "Z" ]); // finds people with surname='Doe' and returns sorted by name descending // ('Z' means DESC; 'A' means ASC - default)

何かを見つけるために渡すことができるオプションは他にもあります. これらのオプションは 2 番目のオブジェクトで渡されます:

1 2
var people = Person.findSync({ surname: "Doe" }, { offset: 2 }); // finds people with surname='Doe', skips the first 2 and returns the others

検索時に生の SQL を使用することもできます.これについては、以下連鎖セクションに記載されています。

Model.countSync([ conditions])

条件に一致するアイテムの数だけをカウントしたい場合は.count()、それらのすべてを見つけてカウントする代わりに、使用することができます. )。

1 2
var count = Person.countSync({ surname: "Doe" }); console.log("We have %d Does in our db", count);

Model.existsSync([ conditions])

と同様に.count()、このメソッドはカウントがゼロより大きいかどうかをチェックするだけです。

1 2
var exists = Person.existsSync({ surname: "Doe" }); console.log("We %s Does in our db", exists ? "have" : "don't have");

Aggregating Functions

Arrayプロパティのは、唯一のいくつかのプロパティを選択するために渡すことができます。アンはObjectまた、条件を定義するために受け入れられています。

使用方法を説明する例を次に示します.groupBy()

1 2 3
//The same as "select avg(weight), age from person where country='someCountry' group by age;" var stats = Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age").getSync(); // stats is an Array, each item should have 'age' and 'avg_weight'

基本.aggregate()メソッド

  • .limit(): 数値を制限として渡すか、2 つの数値をそれぞれオフセットと制限として渡すことができます。
  • .order(): と同じ Model.find().order()

追加の.aggregate()方法

  • min
  • max
  • avg
  • sum
  • count(これへのショートカットがあります- Model.count

ドライバーに応じて、より多くの集計関数があります (たとえば、数学関数)。

Chaining

それほど複雑でない構文が必要な場合は.find()、コールバック パラメーターを指定せずに連鎖せることができます。

1 2 3
var people = Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "surname").runSync(); // finds people with surname='Doe', skips first 2 and limits to 3 elements, // returning only 'name' and 'surname' properties

1 つまたは 2 つのプロパティだけをスキップする場合は、.omit()代わりに を呼び出すことができます.only

連鎖すると、より複雑なクエリが可能になります. たとえば、カスタム SQL を指定して検索できます。

1
Person.find({ age: 18 }).where("LOWER(surname) LIKE ?", ['dea%']).allSync( ... );

SQL パラメータを手動でエスケープすると、エラーが発生しやすくなり、アプリケーションが SQL インジェクションにさらされます.?クエリ内の疑問符を提供されたパラメータで安全に置き換えることにより、構文がエスケープを処理してくれます.複数のwhere句を次のように連鎖させることもできます。必要です。

.find.where&.all同じことを行います; それらはすべて交換可能で連鎖可能です。

orderまたはorderRaw次のこともできます

1 2 3
Person.find({ age: 18 }).order('-name').allSync( ... ); // see the 'Raw queries' section below for more details Person.find({ age: 18 }).orderRaw("?? DESC", ['age']).allSync( ... );

チェーンして、最後にカウントを取得することもできます.この場合、オフセット、制限、順序は無視されます。

1 2
var people = Person.find({ surname: "Doe" }).countSync(); // people = number of people with surname="Doe"

選択したアイテムを削除するオプションも利用できます.連鎖した削除はフックを実行しないことに注意してください.

1 2
Person.find({ surname: "Doe" }).removeSync(); // Does gone..

一般的な配列トラバーサル メソッドを使用してインスタンスに変更を加え、最終的にすべてを保存することもできます。[サポート対象外]

1 2 3 4 5 6 7 8 9 10 11 12 13
Person.find({ surname: "Doe" }).each(function (person) { person.surname = "Dean"; }).save(function (err) { // done! }); Person.find({ surname: "Doe" }).each().filter(function (person) { return person.age >= 18; }).sort(function (person1, person2) { return person1.age < person2.age; }).get(function (people) { // get all people with at least 18 years, sorted by age });

もちろん.find()これを で直接行うこともできますが、より複雑なタスクの場合、これは非常に便利です。

Model.find()あなただけの直接チェーンにすることはできませんので、配列を返しません。あなたが呼び出す必要があり、連鎖を開始するには .each()(あなたがリストをトラバースしたい場合は、オプションのコールバックで)。その後、共通の機能を使用することができ .filter().sort()かつ.forEach()複数回。

最後に (またはプロセス中に..)、次のように呼び出すことができます。

  • .countSync() アイテムの数を知りたい場合。
  • .getSync() リストを取得します。
  • .saveSync() すべてのアイテムの変更を保存します。

条件

条件は、すべてのキーがプロパティ (テーブル列) であるオブジェクトとして定義されます。すべてのキーは、論理的な で連結されることになっていますAND。値は、 を渡さない限り、完全に一致すると見なされますArray。この場合、それは考慮されます。プロパティを比較するリスト。

1 2
{ col1: 123, col2: "foo" } // `col1` = 123 AND `col2` = 'foo' { col1: [ 1, 3, 5 ] } // `col1` IN (1, 3, 5)

他の比較が必要な場合は、いくつかのヘルパー関数によって作成された特別なオブジェクトを使用する必要があります.

1 2 3 4 5 6 7 8 9 10 11
{ col1: orm.eq(123) } // `col1` = 123 (default) { col1: orm.ne(123) } // `col1` <> 123 { col1: orm.gt(123) } // `col1` > 123 { col1: orm.gte(123) } // `col1` >= 123 { col1: orm.lt(123) } // `col1` < 123 { col1: orm.lte(123) } // `col1` <= 123 { col1: orm.between(123, 456) } // `col1` BETWEEN 123 AND 456 { col1: orm.not_between(123, 456) } // `col1` NOT BETWEEN 123 AND 456 { col1: orm.like(12 + "%") } // `col1` LIKE '12%' { col1: orm.not_like(12 + "%") } // `col1` NOT LIKE '12%' { col1: orm.not_in([1, 4, 8]) } // `col1` NOT IN (1, 4, 8)

生のクエリ

1 2 3 4 5 6 7 8 9 10 11 12 13
var data = db.driver.execQuerySync("SELECT id, email FROM user") // You can escape identifiers and values. // For identifier substitution use: ?? // For value substitution use: ? var data = db.driver.execQuerySync( "SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? > ?", ['id', 'name', 'name', 'john', 'id', 55]) // Identifiers don't need to be scaped most of the time var data = db.driver.execQuerySync( "SELECT user.id, user.name FROM user WHERE user.name LIKE ? AND user.id > ?", ['john', 55])

Identity pattern

ID パターンを使用できます (デフォルトではオフになっています)。有効にすると、複数の異なるクエリが同じ結果になり、同じオブジェクトが得られます。データベースを変更できる他のシステムがある場合、またはマニュアルを呼び出す必要がある場合SQL クエリでは、この機能を使用しないでください。また、複雑な自動フェッチ関係で問題が発生することもわかっています。自己責任で使用してください。

モデルごとに有効/無効にすることができます。

1 2 3 4 5
var Person = db.define('person', { name : String }, { identityCache : true });

そしてグローバルにも:

1 2
var db = orm.connectSync('...'); db.settings.set('instance.identityCache', true);

ID キャッシュは、ブール値の代わりに数値を渡すことで、一定期間後に期限切れになるように構成できます。数値は、秒単位でキャッシュ タイムアウトと見なされます (浮動小数点を使用できます)。

: キャッシュに関する 1 つの例外は、インスタンスが保存されていない場合は使用されないことです。たとえば、Person をフェッチしてから変更した場合、保存されない間はキャッシュから渡されません。

アイテムの作成

Model.createSync(items)

データベースに新しい要素を挿入するには、 を使用しますModel.create

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var items = Person.createSync([ { name: "John", surname: "Doe", age: 25, male: true }, { name: "Liza", surname: "Kollan", age: 19, male: false } ]); // items - array of inserted items

アイテムの更新

返されるすべてのアイテムには、モデルに定義されたプロパティと、各アイテムを変更するために使用できるいくつかのメソッドがあります。

1 2 3 4 5
var John = Person.getSync(1); John.name = "Joe"; John.surname = "Doe"; John.saveSync(); console.log("saved!");

インスタンスの更新と保存は、1 回の呼び出しで実行できます。

1 2 3
var John = Person.getSync(1); John.saveSync({ name: "Joe", surname: "Doe" }); console.log("saved!");

インスタンスを削除する場合は、次のようにします。

1 2 3 4
// you could do this without even fetching it, look at Chaining section above var John = Person.getSync(1); John.removeSync(); console.log("removed!");

検証

wiki の情報を参照してください

協会

アソシエーションは、1 つ以上のテーブル間の関係です。

hasOne

Aは一つのために多くのそれは、ASは、同じで関係です。に属しています。
例:Animal.hasOne('owner', Person)
。動物は、唯一のワンオーナーを持っていことができる多くのことができますが、人の動物持っている
意志によって動物をで持ってきowner_id自動的に追加プロパティ。

以下の機能が利用可能になります。

1 2 3 4
animal.getOwnerSync() // Gets owner animal.setOwnerSync(person) // Sets owner_id animal.hasOwnerSync() // Checks if owner exists animal.removeOwnerSync() // Sets owner_id to 0

チェーン検索

hasOne アソシエーションもチェーン検索と互換性があります. 上記の例を使用すると、これを実行して ChainFind オブジェクトの新しいインスタンスにアクセスできます。

1
Animal.findByOwner({ /* options */ })

逆アクセス

1
Animal.hasOne('owner', Person, {reverse: 'pets'})

以下を追加します。

1 2 3 4 5 6
// Instance methods person.getPetsSync(function..) person.setPetsSync(cat, function..) // Model methods Person.findByPets({ /* options */ }) // returns ChainFind object

hasMany

IS多対多の関係(参加表を含みます)。
のEg: 。Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients', key: true })
患者の各CANドクター医師がMANYできるさまざまな異なる患者が多くを持っていていています。

これにより、patient_doctors次の呼び出し時に結合テーブルが作成されますPatient.sync()

列名 タイプ
患者ID 整数 (複合キー)
Doctor_id 整数 (複合キー)
なぜ varchar(255)

次の機能が使用可能になります。

1 2 3 4 5 6 7 8 9 10 11 12
patient.getDoctorsSync() // List of doctors patient.addDoctorsSync(docs) // Adds entries to join table patient.setDoctorsSync(docs) // Removes existing entries in join table, adds new ones patient.hasDoctorsSync(docs) // Checks if patient is associated to specified doctors patient.removeDoctorsSync(docs) // Removes specified doctors from join table doctor.getPatientsSync() etc... // You can also do: patient.doctors = [doc1, doc2]; patient.saveSync()

医師を患者に関連付けるには:

1
patient.addDoctorSync(surgeon, {why: "remove appendix"})

{patient_id: 4, doctor_id: 6, why: "remove appendix"}結合テーブルに追加されます。

getAccessor

このタイプの関連付けのこのアクセサーはChainFind、コールバックを渡さない場合に を返します。これは、次のようなことができることを意味します。

1 2
var doctors = patient.getDoctors().order("name").offset(1).runSync()); // ... all doctors, ordered by name, excluding first one

extendsTo

オプションのプロパティを別のテーブルまたはコレクションに分割したい場合は、すべての拡張機能が新しいテーブルにあり、各行の一意の識別子がメイン モデル インスタンス ID です。例:

1 2 3 4 5 6 7
var Person = db.define("person", { name : String }); var PersonAddress = Person.extendsTo("address", { street : String, number : Number });

テーブルの作成はperson、列idを使用してこれname作成しますおよび.person_address列を使用してテーブル作成しますperson_id,streetおよびnumber. PersonAN と同様モデルのメソッドで使用できhasOne ます アソシエーション. この例.getAddress(cb)では.setAddress(Address, cb)呼び出すことができますか, , ..

注:からの結果を保存する必要はありませんPerson.extendsTo. 拡張モデルを返します. この拡張テーブルを直接クエリするために使用できます (関連するモデルを見つけることもできます) が、それはあなた次第です.元のモデルを使用すると、返品を破棄できます。

Examples & options

1 対 n の関係がある場合は、関連付けを使用する必要がありますhasOne(所属)。

1 2 3 4 5 6 7 8 9 10 11 12 13
var Person = db.define('person', { name : String }); var Animal = db.define('animal', { name : String }); Animal.hasOne("owner", Person); // creates column 'owner_id' in 'animal' table // get animal with id = 123 var animal = Animal.getSync(123); // animal is the animal model instance, if found var person = animal.getOwnerSync(); // if animal has really an owner, person points to it

owner_idrequiredオプションを指定することにより、データベースでフィールドを必須としてマークできます。

1
Animal.hasOne("owner", Person, { required: true });

フィールドが必須ではないが、フィールドが存在しない場合でも検証する必要がある場合は、alwaysValidateオプションを指定します (これは、たとえば、null フィールドの検証がレコード内の他のフィールドに依存している場合に発生する可能性があります)。

1
Animal.hasOne("owner", Person, { required: false, alwaysValidate: true });

フィールド (owner_id) に別の名前を使用する場合は、設定でこのパラメーターを変更できます。

1
db.settings.set("properties.association_key", "{field}_{name}"); // {name} will be replaced by 'owner' and {field} will be replaced by 'id' in this case

注: これは、関連付けを指定する前に行う必要があります。

hasMany関連は関連テーブルに追加の特性を有することができます。

1 2 3 4 5 6 7 8 9 10 11
var Person = db.define('person', { name : String }); Person.hasMany("friends", { rate : Number }, {}, { key: true }); var John = Person.getSync(123); var friends = John.getFriendsSync(); // assumes rate is another column on table person_friends // you can access it by going to friends[N].extra.rate

ご希望の場合は、有効にすることができautoFetch。あなたは、モデルのインスタンスを取得したり、見つけたとき団体が自動的にフェッチされている。この方法を。

1 2 3 4 5 6 7 8 9 10 11 12
var Person = db.define('person', { name : String }); Person.hasMany("friends", { rate : Number }, { key : true, // Turns the foreign keys in the join table into a composite key autoFetch : true }); var John = Person.getSync(123); // no need to do John.getFriends() , John already has John.friends Array

このオプションは、関連付けごとではなくグローバルに定義することもできます。

1 2 3 4 5 6 7 8 9 10
var Person = db.define('person', { name : String }, { autoFetch : true }); Person.hasMany("friends", { rate : Number }, { key: true });

関連付けは、reverseオプションを使用して、関連付けられたモデルを呼び出すことができます。たとえば、ModelA から ModelB への関連付けがある場合、ModelB にアクセサーを作成して、ModelA からインスタンスを取得できます。混乱していますか? 次の例を見てください。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var Pet = db.define('pet', { name : String }); var Person = db.define('person', { name : String }); Pet.hasOne("owner", Person, { reverse : "pets" }); var pets = Person(4).getPetsSync(); // although the association was made on Pet, // Person will have an accessor (getPets) // // In this example, ORM will fetch all pets // whose owner_id = 4

これは 、両側から多対多の関連付けhasMany管理できるため、関連付けを行う場合にはさらに意味があります

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var Pet = db.define('pet', { name : String }); var Person = db.define('person', { name : String }); Person.hasMany("pets", Pet, { bought : Date }, { key : true, reverse : "owners" }); Person(1).getPetsSync(...); Pet(2).getOwnersSync(...);

取引支援

低レベルのトランザクション関数を使用して、db トランザクションを処理できます。

1 2 3 4 5 6
db.begin(); ... if(err) db.rollback(); else db.commit();

または、trans を使用して単純な処理を行うこともできます。

1 2 3 4
var result = db.trans(() => { ... return result; });

外部データベース アダプタの追加

外部データベース アダプタを に追加するormには、addAdapterメソッドを呼び出し、アダプタのコンストラクタとともに、このアダプタとの接続に使用するエイリアスを渡します。

1
require('orm').addAdapter('cassandra', CassandraAdapter);

見る the documentation for creating adapters 詳細については。