{"id":13462934,"url":"https://github.com/dresende/node-orm2","last_synced_at":"2025-05-14T04:06:43.882Z","repository":{"id":5660425,"uuid":"6869690","full_name":"dresende/node-orm2","owner":"dresende","description":"Object Relational Mapping","archived":false,"fork":false,"pushed_at":"2025-03-13T13:37:02.000Z","size":2429,"stargazers_count":3062,"open_issues_count":218,"forks_count":374,"subscribers_count":112,"default_branch":"master","last_synced_at":"2025-05-11T02:44:38.066Z","etag":null,"topics":["database","mongodb","mysql","orm","postgresql","redshift","sqlite"],"latest_commit_sha":null,"homepage":"http://github.com/dresende/node-orm2","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dresende.png","metadata":{"files":{"readme":"Readme.md","changelog":"Changelog.md","contributing":"Contributing.md","funding":null,"license":"License","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-11-26T17:49:45.000Z","updated_at":"2025-05-04T20:43:08.000Z","dependencies_parsed_at":"2022-08-08T21:15:11.266Z","dependency_job_id":"fe215b6b-d978-4be5-8fa3-c4d82517e6ee","html_url":"https://github.com/dresende/node-orm2","commit_stats":{"total_commits":1382,"total_committers":77,"mean_commits":"17.948051948051948","dds":"0.37047756874095517","last_synced_commit":"b1ff6341b3e5e8be308cd3b822253c69bb87b11c"},"previous_names":[],"tags_count":72,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dresende%2Fnode-orm2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dresende%2Fnode-orm2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dresende%2Fnode-orm2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dresende%2Fnode-orm2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dresende","download_url":"https://codeload.github.com/dresende/node-orm2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254067589,"owners_count":22009217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","mongodb","mysql","orm","postgresql","redshift","sqlite"],"created_at":"2024-07-31T13:00:41.372Z","updated_at":"2025-05-14T04:06:43.728Z","avatar_url":"https://github.com/dresende.png","language":"JavaScript","readme":"## Object Relational Mapping\n\n[![Build Status](https://api.travis-ci.org/dresende/node-orm2.svg?branch=master)](http://travis-ci.org/dresende/node-orm2)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fdresende%2Fnode-orm2.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fdresende%2Fnode-orm2?ref=badge_shield)\n[![](https://badge.fury.io/js/orm.svg)](https://npmjs.org/package/orm)\n[![](https://gemnasium.com/dresende/node-orm2.svg)](https://gemnasium.com/dresende/node-orm2)\n[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=dresende\u0026url=https://github.com/dresende/node-orm2\u0026title=ORM\u0026language=\u0026tags=github\u0026category=software)\n\n## This package is not actively maintained\n\nIf you're starting a new project, consider using one of the following instead as they have a more active community:\n* https://github.com/typeorm/typeorm\n* https://github.com/sequelize/sequelize\n\n\n## Install\n\n```sh\nnpm install orm\n```\n\n## Node.js Version Support\n\nSupported: 4.0 +\n\nIf using Nodejs \u003e= 14 \u0026 Postgres, you must use `pg` driver \u003e= 8.1. v7 doesn't work correctly (tests time out).\n\nTests are run on [Travis CI](https://travis-ci.org/)\nIf you want you can run tests locally:\n\n```sh\nnpm test\n```\n\n## DBMS Support\n\n- MySQL \u0026 MariaDB\n- PostgreSQL\n- Amazon Redshift\n- SQLite\n- MongoDB (beta, node 6 or older, doesn't work with node 8. Also, missing aggregation features)\n\n## Features\n\n- Create Models, sync, drop, bulk create, get, find, remove, count, aggregated functions\n- Create Model associations, find, check, create and remove\n- Define custom validations (several builtin validations, check instance properties before saving - see [enforce](http://github.com/dresende/node-enforce) for details)\n- Model instance caching and integrity (table rows fetched twice are the same object, changes to one change all)\n- Plugins: [MySQL FTS](http://dresende.github.io/node-orm-mysql-fts) , [Pagination](http://dresende.github.io/node-orm-paging) , [Transaction](http://dresende.github.io/node-orm-transaction), [Timestamps](http://github.com/SPARTAN563/node-orm-timestamps), [Migrations](https://github.com/locomote/node-migrate-orm2)\n\n## Introduction\n\nThis is a node.js object relational mapping module.\n\nAn example:\n\n```js\nvar orm = require(\"orm\");\n\norm.connect(\"mysql://username:password@host/database\", function (err, db) {\n  if (err) throw err;\n\n  var Person = db.define(\"person\", {\n    name      : String,\n    surname   : String,\n    age       : Number, // FLOAT\n    male      : Boolean,\n    continent : [ \"Europe\", \"America\", \"Asia\", \"Africa\", \"Australia\", \"Antarctica\" ], // ENUM type\n    photo     : Buffer, // BLOB/BINARY\n    data      : Object // JSON encoded\n  }, {\n    methods: {\n      fullName: function () {\n        return this.name + ' ' + this.surname;\n      }\n    },\n    validations: {\n      age: orm.enforce.ranges.number(18, undefined, \"under-age\")\n    }\n  });\n\n  // add the table to the database\n  db.sync(function(err) {\n    if (err) throw err;\n\n    // add a row to the person table\n    Person.create({ id: 1, name: \"John\", surname: \"Doe\", age: 27 }, function(err) {\n      if (err) throw err;\n\n      // query the person table by surname\n      Person.find({ surname: \"Doe\" }, function (err, people) {\n        // SQL: \"SELECT * FROM person WHERE surname = 'Doe'\"\n        if (err) throw err;\n\n        console.log(\"People found: %d\", people.length);\n        console.log(\"First person: %s, age %d\", people[0].fullName(), people[0].age);\n\n        people[0].age = 16;\n        people[0].save(function (err) {\n          // err.msg == \"under-age\";\n        });\n      });\n    });\n  });\n});\n```\n\n-------\n\n## Express\n\nIf you're using Express, you might want to use the simple middleware to integrate more easily.\n\n```js\nvar express = require('express');\nvar orm = require('orm');\nvar app = express();\n\napp.use(orm.express(\"mysql://username:password@host/database\", {\n\tdefine: function (db, models, next) {\n\t\tmodels.person = db.define(\"person\", { ... });\n\t\tnext();\n\t}\n}));\napp.listen(80);\n\napp.get(\"/\", function (req, res) {\n\t// req.models is a reference to models used above in define()\n\treq.models.person.find(...);\n});\n```\n\nYou can call `orm.express` more than once to have multiple database connections. Models defined across connections\nwill be joined together in `req.models`. **Don't forget to use it before `app.use(app.router)`, preferably right after your\nassets public folder(s).**\n\n## Examples\n\nSee `examples/anontxt` for an example express based app.\n\n## Documentation\n\nDocumentation is moving to the [wiki](https://github.com/dresende/node-orm2/wiki/).\n\n## Settings\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Settings).\n\n## Connecting\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Connecting-to-Database).\n\n## Models\n\nA Model is an abstraction over one or more database tables. Models support associations (more below). The name of the model is assumed to match the table name.\n\nModels support behaviours for accessing and manipulating table data.\n\n## Defining Models\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Defining-Models).\n\n### Properties\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Properties).\n\n### Instance Methods\n\nAre passed in during model definition.\n\n```js\nvar Person = db.define('person', {\n    name    : String,\n    surname : String\n}, {\n    methods: {\n        fullName: function () {\n            return this.name + ' ' + this.surname;\n        }\n    }\n});\n\nPerson.get(4, function(err, person) {\n    console.log( person.fullName() );\n})\n```\n\n### Model Methods\n\nAre defined directly on the model.\n\n```js\nvar Person = db.define('person', {\n    name    : String,\n    height  : { type: 'integer' }\n});\nPerson.tallerThan = function(height, callback) {\n    this.find({ height: orm.gt(height) }, callback);\n};\n\nPerson.tallerThan( 192, function(err, tallPeople) { ... } );\n```\n\n\n## Loading Models\n\nModels can be in separate modules. Simply ensure that the module holding the models uses module.exports to publish a function that accepts the database connection, then load your models however you like.\n\nNote - using this technique you can have cascading loads.\n\n```js\n// your main file (after connecting)\ndb.load(\"./models\", function (err) {\n  // loaded!\n  var Person = db.models.person;\n  var Pet    = db.models.pet;\n});\n\n// models.js\nmodule.exports = function (db, cb) {\n  db.load(\"./models-extra\", function (err) {\n    if (err) {\n      return cb(err);\n    }\n\n    db.define('person', {\n      name : String\n    });\n\n    return cb();\n  });\n};\n\n// models-extra.js\nmodule.exports = function (db, cb) {\n  db.define('pet', {\n      name : String\n  });\n\n  return cb();\n};\n```\n\n## Synchronizing Models\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Syncing-and-dropping-models).\n\n## Dropping Models\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Syncing-and-dropping-models).\n\n## Advanced Options\n\nORM2 allows you some advanced tweaks on your Model definitions. You can configure these via settings or in the call to `define` when you setup the Model.\n\nFor example, each Model instance has a unique ID in the database. This table column is added automatically, and called \"id\" by default.\u003cbr/\u003e\nIf you define your own `key: true` column, \"id\" will not be added:\n\n```js\nvar Person = db.define(\"person\", {\n\tpersonId : { type: 'serial', key: true },\n\tname     : String\n});\n\n// You can also change the default \"id\" property name globally:\ndb.settings.set(\"properties.primary_key\", \"UID\");\n\n// ..and then define your Models\nvar Pet = db.define(\"pet\", {\n\tname : String\n});\n```\n\n**Pet** model will have 2 columns, an `UID` and a `name`.\n\nIt's also possible to have composite keys:\n\n```js\nvar Person = db.define(\"person\", {\n\tfirstname : { type: 'text', key: true },\n\tlastname  : { type: 'text', key: true }\n});\n```\n\nOther options:\n\n- `identityCache`  : (default: `false`) Set it to `true` to enable identity cache ([Singletons](#singleton)) or set a timeout value (in seconds);\n- `autoSave`       : (default: `false`) Set it to `true` to save an Instance right after changing any property;\n- `autoFetch`      : (default: `false`) Set it to `true` to fetch associations when fetching an instance from the database;\n- `autoFetchLimit` : (default: `1`) If `autoFetch` is enabled this defines how many hoops (associations of associations)\n  you want it to automatically fetch.\n\n## Hooks\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Hooks).\n\n## Finding Items\n\n### Model.get(id, [ options ], cb)\n\nTo get a specific element from the database use `Model.get`.\n\n```js\nPerson.get(123, function (err, person) {\n\t// finds person with id = 123\n});\n```\n\n### Model.find([ conditions ] [, options ] [, limit ] [, order ] [, cb ])\n\nFinding one or more elements has more options, each one can be given in no specific parameter order. Only `options` has to be after `conditions` (even if it's an empty object).\n\n```js\nPerson.find({ name: \"John\", surname: \"Doe\" }, 3, function (err, people) {\n\t// finds people with name='John' AND surname='Doe' and returns the first 3\n});\n```\n\nIf you need to sort the results because you're limiting or just because you want them sorted do:\n\n```js\nPerson.find({ surname: \"Doe\" }, \"name\", function (err, people) {\n\t// finds people with surname='Doe' and returns sorted by name ascending\n});\nPerson.find({ surname: \"Doe\" }, [ \"name\", \"Z\" ], function (err, people) {\n\t// finds people with surname='Doe' and returns sorted by name descending\n\t// ('Z' means DESC; 'A' means ASC - default)\n});\n```\n\nThere are more options that you can pass to find something. These options are passed in a second object:\n\n```js\nPerson.find({ surname: \"Doe\" }, { offset: 2 }, function (err, people) {\n\t// finds people with surname='Doe', skips the first 2 and returns the others\n});\n```\n\nYou can also use raw SQL when searching. It's documented in the *Chaining* section below.\n\n### Model.count([ conditions, ] cb)\n\nIf you just want to count the number of items that match a condition you can just use `.count()` instead of finding all\nof them and counting. This will actually tell the database server to do a count (it won't be done in the node process itself).\n\n```js\nPerson.count({ surname: \"Doe\" }, function (err, count) {\n\tconsole.log(\"We have %d Does in our db\", count);\n});\n```\n\n### Model.exists([ conditions, ] cb)\n\nSimilar to `.count()`, this method just checks if the count is greater than zero or not.\n\n```js\nPerson.exists({ surname: \"Doe\" }, function (err, exists) {\n\tconsole.log(\"We %s Does in our db\", exists ? \"have\" : \"don't have\");\n});\n```\n\n### Aggregating Functions\n\nIf you need to get some aggregated values from a Model, you can use `Model.aggregate()`. Here's an example to better\nillustrate:\n\n```js\nPerson.aggregate({ surname: \"Doe\" }).min(\"age\").max(\"age\").get(function (err, min, max) {\n\tconsole.log(\"The youngest Doe guy has %d years, while the oldest is %d\", min, max);\n});\n```\n\nAn `Array` of properties can be passed to select only a few properties. An `Object` is also accepted to define conditions.\n\nHere's an example to illustrate how to use `.groupBy()`:\n\n```js\n//The same as \"select avg(weight), age from person where country='someCountry' group by age;\"\nPerson.aggregate([\"age\"], { country: \"someCountry\" }).avg(\"weight\").groupBy(\"age\").get(function (err, stats) {\n  // stats is an Array, each item should have 'age' and 'avg_weight'\n});\n```\n\n### Base `.aggregate()` methods\n\n- `.limit()`: you can pass a number as a limit, or two numbers as offset and limit respectively\n- `.order()`: same as `Model.find().order()`\n\n### Additional `.aggregate()` methods\n\n- `min`\n- `max`\n- `avg`\n- `sum`\n- `count` (there's a shortcut to this - `Model.count`)\n\nThere are more aggregate functions depending on the driver (Math functions for example).\n\n### Chaining\n\nIf you prefer less complicated syntax you can chain `.find()` by not giving a callback parameter.\n\n```js\nPerson.find({ surname: \"Doe\" }).limit(3).offset(2).only(\"name\", \"surname\").run(function (err, people) {\n    // finds people with surname='Doe', skips first 2 and limits to 3 elements,\n    // returning only 'name' and 'surname' properties\n});\n```\nIf you want to skip just one or two properties, you can call `.omit()` instead of `.only`.\n\nChaining allows for more complicated queries. For example, we can search by specifying custom SQL:\n```js\nPerson.find({ age: 18 }).where(\"LOWER(surname) LIKE ?\", ['dea%']).all( ... );\n```\nIt's bad practice to manually escape SQL parameters as it's error prone and exposes your application to SQL injection.\nThe `?` syntax takes care of escaping for you, by safely substituting the question mark in the query with the parameters provided.\nYou can also chain multiple `where` clauses as needed.\n\n`.find`, `.where` \u0026 `.all` do the same thing; they are all interchangeable and chainable.\n\nYou can also `order` or `orderRaw`:\n```js\nPerson.find({ age: 18 }).order('-name').all( ... );\n// see the 'Raw queries' section below for more details\nPerson.find({ age: 18 }).orderRaw(\"?? DESC\", ['age']).all( ... );\n```\n\nYou can also chain and just get the count in the end. In this case, offset, limit and order are ignored.\n\n```js\nPerson.find({ surname: \"Doe\" }).count(function (err, people) {\n  // people = number of people with surname=\"Doe\"\n});\n```\n\nAlso available is the option to remove the selected items.\nNote that a chained remove will not run any hooks.\n\n```js\nPerson.find({ surname: \"Doe\" }).remove(function (err) {\n  // Does gone..\n});\n```\n\nYou can also make modifications to your instances using common Array traversal methods and save everything\nin the end.\n\n```js\nPerson.find({ surname: \"Doe\" }).each(function (person) {\n\tperson.surname = \"Dean\";\n}).save(function (err) {\n\t// done!\n});\n\nPerson.find({ surname: \"Doe\" }).each().filter(function (person) {\n\treturn person.age \u003e= 18;\n}).sort(function (person1, person2) {\n\treturn person1.age \u003c person2.age;\n}).get(function (people) {\n\t// get all people with at least 18 years, sorted by age\n});\n```\n\nOf course you could do this directly on `.find()`, but for some more complicated tasks this can be very usefull.\n\n`Model.find()` does not return an Array so you can't just chain directly. To start chaining you have to call\n`.each()` (with an optional callback if you want to traverse the list). You can then use the common functions\n`.filter()`, `.sort()` and `.forEach()` more than once.\n\nIn the end (or during the process..) you can call:\n- `.count()` if you just want to know how many items there are;\n- `.get()` to retrieve the list;\n- `.save()` to save all item changes.\n\n#### Conditions\n\nConditions are defined as an object where every key is a property (table column). All keys are supposed\nto be concatenated by the logical `AND`. Values are considered to match exactly, unless you're passing\nan `Array`. In this case it is considered a list to compare the property with.\n\n```js\n{ col1: 123, col2: \"foo\" } // `col1` = 123 AND `col2` = 'foo'\n{ col1: [ 1, 3, 5 ] } // `col1` IN (1, 3, 5)\n```\n\nIf you need other comparisons, you have to use a special object created by some helper functions. Here are\na few examples to describe it:\n\n```js\n{ col1: orm.eq(123) } // `col1` = 123 (default)\n{ col1: orm.ne(123) } // `col1` \u003c\u003e 123\n{ col1: orm.gt(123) } // `col1` \u003e 123\n{ col1: orm.gte(123) } // `col1` \u003e= 123\n{ col1: orm.lt(123) } // `col1` \u003c 123\n{ col1: orm.lte(123) } // `col1` \u003c= 123\n{ col1: orm.between(123, 456) } // `col1` BETWEEN 123 AND 456\n{ col1: orm.not_between(123, 456) } // `col1` NOT BETWEEN 123 AND 456\n{ col1: orm.like(12 + \"%\") } // `col1` LIKE '12%'\n{ col1: orm.not_like(12 + \"%\") } // `col1` NOT LIKE '12%'\n{ col1: orm.not_in([1, 4, 8]) } // `col1` NOT IN (1, 4, 8)\n```\n\n#### Raw queries\n\n```js\ndb.driver.execQuery(\"SELECT id, email FROM user\", function (err, data) { ... })\n\n// You can escape identifiers and values.\n// For identifier substitution use: ??\n// For value substitution use: ?\ndb.driver.execQuery(\n  \"SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? \u003e ?\",\n  ['id', 'name', 'name', 'john', 'id', 55],\n  function (err, data) { ... }\n)\n\n// Identifiers don't need to be scaped most of the time\ndb.driver.execQuery(\n  \"SELECT user.id, user.name FROM user WHERE user.name LIKE ? AND user.id \u003e ?\",\n  ['john', 55],\n  function (err, data) { ... }\n)\n```\n\n### Identity pattern\n\nYou can use the identity pattern (turned off by default). If enabled, multiple different queries will result in the same result - you will\nget the same object. If you have other systems that can change your database or you need to call some manual SQL queries,\nyou shouldn't use this feature. It is also know to cause some problems with complex\nautofetch relationships. Use at your own risk.\n\nIt can be enabled/disabled per model:\n\n```js\nvar Person = db.define('person', {\n\tname          : String\n}, {\n\tidentityCache : true\n});\n```\n\nand also globally:\n\n```js\norm.connect('...', function(err, db) {\n  db.settings.set('instance.identityCache', true);\n});\n```\n\nThe identity cache can be configured to expire after a period of time by passing in a number instead of a\nboolean. The number will be considered the cache timeout in seconds (you can use floating point).\n\n**Note**: One exception about Caching is that it won't be used if an instance is not saved. For example, if\nyou fetch a Person and then change it, while it doesn't get saved it won't be passed from Cache.\n\n## Creating Items\n\n### Model.create(items, cb)\n\nTo insert new elements to the database use `Model.create`.\n\n```js\nPerson.create([\n\t{\n\t\tname: \"John\",\n\t\tsurname: \"Doe\",\n\t\tage: 25,\n\t\tmale: true\n\t},\n\t{\n\t\tname: \"Liza\",\n\t\tsurname: \"Kollan\",\n\t\tage: 19,\n\t\tmale: false\n\t}\n], function (err, items) {\n\t// err - description of the error or null\n\t// items - array of inserted items\n});\n```\n\n## Updating Items\n\nEvery item returned has the properties that were defined to the Model and also a couple of methods you can\nuse to change each item.\n\n```js\nPerson.get(1, function (err, John) {\n\tJohn.name = \"Joe\";\n\tJohn.surname = \"Doe\";\n\tJohn.save(function (err) {\n\t\tconsole.log(\"saved!\");\n\t});\n});\n```\n\nUpdating and then saving an instance can be done in a single call:\n\n```js\nPerson.get(1, function (err, John) {\n\tJohn.save({ name: \"Joe\", surname: \"Doe\" }, function (err) {\n\t\tconsole.log(\"saved!\");\n\t});\n});\n```\n\nIf you want to remove an instance, just do:\n\n```js\n// you could do this without even fetching it, look at Chaining section above\nPerson.get(1, function (err, John) {\n\tJohn.remove(function (err) {\n\t\tconsole.log(\"removed!\");\n\t});\n});\n```\n\n## Validations\n\nSee information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Validations).\n\n## Associations\n\nAn association is a relation between one or more tables.\n\n### hasOne\n\nIs a **many to one** relationship. It's the same as **belongs to.**\u003cbr/\u003e\nEg: `Animal.hasOne('owner', Person)`.\u003cbr/\u003e\nAnimal can only have one owner, but Person can have many animals.\u003cbr/\u003e\nAnimal will have the `owner_id` property automatically added.\n\nThe following functions will become available:\n```js\nanimal.getOwner(function..)         // Gets owner\nanimal.setOwner(person, function..) // Sets owner_id\nanimal.hasOwner(function..)         // Checks if owner exists\nanimal.removeOwner()                // Sets owner_id to 0\n```\n\n**Chain Find**\n\nThe hasOne association is also chain find compatible. Using the example above, we can do this to access a new instance of a ChainFind object:\n\n```js\nAnimal.findByOwner({ /* options */ })\n```\n\n**Reverse access**\n\n```js\nAnimal.hasOne('owner', Person, {reverse: 'pets'})\n```\n\nwill add the following:\n\n```js\n// Instance methods\nperson.getPets(function..)\nperson.setPets(cat, function..)\n\n// Model methods\nPerson.findByPets({ /* options */ }) // returns ChainFind object\n```\n\n### hasMany\n\nIs a **many to many** relationship (includes join table).\u003cbr/\u003e\nEg: `Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients', key: true })`.\u003cbr/\u003e\nPatient can have many different doctors. Each doctor can have many different patients.\n\nThis will create a join table `patient_doctors` when you call `Patient.sync()`:\n\n column name | type\n :-----------|:--------\n patient_id  | Integer (composite key)\n doctor_id   | Integer (composite key)\n why         | varchar(255)\n\nThe following functions will be available:\n\n```js\npatient.getDoctors(function..)           // List of doctors\npatient.addDoctors(docs, function...)    // Adds entries to join table\npatient.setDoctors(docs, function...)    // Removes existing entries in join table, adds new ones\npatient.hasDoctors(docs, function...)    // Checks if patient is associated to specified doctors\npatient.removeDoctors(docs, function...) // Removes specified doctors from join table\n\ndoctor.getPatients(function..)\netc...\n\n// You can also do:\npatient.doctors = [doc1, doc2];\npatient.save(...)\n```\n\nTo associate a doctor to a patient:\n\n```js\npatient.addDoctor(surgeon, {why: \"remove appendix\"}, function(err) { ... } )\n```\n\nwhich will add `{patient_id: 4, doctor_id: 6, why: \"remove appendix\"}` to the join table.\n\n#### getAccessor\n\nThis accessor in this type of association returns a `ChainFind` if not passing a callback. This means you can\ndo things like:\n\n```js\npatient.getDoctors().order(\"name\").offset(1).run(function (err, doctors), {\n\t// ... all doctors, ordered by name, excluding first one\n});\n```\n\n### extendsTo\n\nIf you want to split maybe optional properties into different tables or collections. Every extension will be in a new table,\nwhere the unique identifier of each row is the main model instance id. For example:\n\n```js\nvar Person = db.define(\"person\", {\n    name : String\n});\nvar PersonAddress = Person.extendsTo(\"address\", {\n    street : String,\n    number : Number\n});\n```\n\nThis will create a table `person` with columns `id` and `name`. The extension will create a table `person_address` with\ncolumns `person_id`, `street` and `number`. The methods available in the `Person` model are similar to an `hasOne`\nassociation. In this example you would be able to call `.getAddress(cb)`, `.setAddress(Address, cb)`, ..\n\n**Note:** you don't have to save the result from `Person.extendsTo`. It returns an extended model. You can use it to query\ndirectly this extended table (and even find the related model) but that's up to you. If you only want to access it using the\noriginal model you can just discard the return.\n\n### Examples \u0026 options\n\nIf you have a relation of 1 to n, you should use `hasOne` (belongs to) association.\n\n```js\nvar Person = db.define('person', {\n  name : String\n});\nvar Animal = db.define('animal', {\n  name : String\n});\nAnimal.hasOne(\"owner\", Person); // creates column 'owner_id' in 'animal' table\n\n// get animal with id = 123\nAnimal.get(123, function (err, animal) {\n  // animal is the animal model instance, if found\n  animal.getOwner(function (err, person) {\n    // if animal has really an owner, person points to it\n  });\n});\n```\n\nYou can mark the `owner_id` field as required in the database by specifying the `required` option:\n```js\nAnimal.hasOne(\"owner\", Person, { required: true });\n```\n\nIf a field is not required, but should be validated even if it is not present, then specify the `alwaysValidate` option.\n(this can happen, for example when validation of a null field depends on other fields in the record)\n```js\nAnimal.hasOne(\"owner\", Person, { required: false, alwaysValidate: true });\n```\n\nIf you prefer to use another name for the field (owner_id) you can change this parameter in the settings.\n\n```js\ndb.settings.set(\"properties.association_key\", \"{field}_{name}\"); // {name} will be replaced by 'owner' and {field} will be replaced by 'id' in this case\n```\n\n**Note: This has to be done before the association is specified.**\n\nThe `hasMany` associations can have additional properties in the association table.\n\n```js\nvar Person = db.define('person', {\n    name : String\n});\nPerson.hasMany(\"friends\", {\n  rate : Number\n}, {}, { key: true });\n\nPerson.get(123, function (err, John) {\n  John.getFriends(function (err, friends) {\n    // assumes rate is another column on table person_friends\n    // you can access it by going to friends[N].extra.rate\n  });\n});\n```\n\nIf you prefer you can activate `autoFetch`.\nThis way associations are automatically fetched when you get or find instances of a model.\n\n```js\nvar Person = db.define('person', {\n  name : String\n});\nPerson.hasMany(\"friends\", {\n  rate : Number\n}, {\n  key       : true, // Turns the foreign keys in the join table into a composite key\n  autoFetch : true\n});\n\nPerson.get(123, function (err, John) {\n    // no need to do John.getFriends() , John already has John.friends Array\n});\n```\n\nYou can also define this option globally instead of a per association basis.\n\n```js\nvar Person = db.define('person', {\n  name : String\n}, {\n    autoFetch : true\n});\nPerson.hasMany(\"friends\", {\n  rate : Number\n}, {\n  key: true\n});\n```\n\nAssociations can make calls to the associated Model by using the `reverse` option. For example, if you have an\nassociation from ModelA to ModelB, you can create an accessor in ModelB to get instances from ModelA.\nConfusing? Look at the next example.\n\n```js\nvar Pet = db.define('pet', {\n  name : String\n});\nvar Person = db.define('person', {\n  name : String\n});\nPet.hasOne(\"owner\", Person, {\n  reverse : \"pets\"\n});\n\nPerson(4).getPets(function (err, pets) {\n  // although the association was made on Pet,\n  // Person will have an accessor (getPets)\n  //\n  // In this example, ORM will fetch all pets\n  // whose owner_id = 4\n});\n```\n\nThis makes even more sense when having `hasMany` associations since you can manage the *many to many*\nassociations from both sides.\n\n```js\nvar Pet = db.define('pet', {\n  name : String\n});\nvar Person = db.define('person', {\n  name : String\n});\nPerson.hasMany(\"pets\", Pet, {\n  bought  : Date\n}, {\n  key     : true,\n  reverse : \"owners\"\n});\n\nPerson(1).getPets(...);\nPet(2).getOwners(...);\n```\n\n------\n\n## Promise support\n\nORM supports Promises via [bluebird](http://bluebirdjs.com/docs/api-reference.html).\nMost methods which accept a callback have a Promise version whith a `Async` postfix.\nEg:\n```js\norm.connectAsync().then().catch();\nPerson.getAsync(1).then();\nPerson.find({ age: 18 }).where(\"LOWER(surname) LIKE ?\", ['dea%']).allAsync( ... );\nPerson.aggregate({ surname: \"Doe\" }).min(\"age\").max(\"age\").getAsync();\n\n```\nThe exception here are hooks, which should return a Promise if they perform asynchronous operations:\n```js\nbeforeCreate: function () {\n  return new Promise(function(resolve, reject) {\n    doSomeStuff().then(resolve);\n  }\n```\n\n## Adding external database adapters\n\nTo add an external database adapter to `orm`, call the `addAdapter` method, passing in the alias to use for connecting\nwith this adapter, along with the constructor for the adapter:\n\n```js\nrequire('orm').addAdapter('cassandra', CassandraAdapter);\n```\n\nSee [the documentation for creating adapters](./Adapters.md) for more details.\n\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fdresende%2Fnode-orm2.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fdresende%2Fnode-orm2?ref=badge_large)\n","funding_links":[],"categories":["ORM","JavaScript","Packages","Number"],"sub_categories":["Database","Database ODM / ORM"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdresende%2Fnode-orm2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdresende%2Fnode-orm2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdresende%2Fnode-orm2/lists"}