Blame view

Readme.md 25.2 KB
86bb9477   Diogo Resende   Adds initial Readme
1
2
  ## Object Relational Mapping
  
67dbb8bf   Mithgol   use SVG to displa...
3
4
  [![Build Status](https://api.travis-ci.org/dresende/node-orm2.svg?branch=master)](http://travis-ci.org/dresende/node-orm2)
  [![](https://badge.fury.io/js/orm.svg)](https://npmjs.org/package/orm)
5ba9aa67   Diogo Resende   Adds dependency s...
5
  [![](https://gemnasium.com/dresende/node-orm2.png)](https://gemnasium.com/dresende/node-orm2)
6183d3f2   Diogo Resende   Adds Flattr badge...
6
  [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=dresende&url=https://github.com/dresende/node-orm2&title=ORM&language=&tags=github&category=software)
868f33c9   Diogo Resende   Changes Readme to...
7
  
85017a9e   Diogo Resende   Changes Readme to...
8
  ## Install
86bb9477   Diogo Resende   Adds initial Readme
9
  
85017a9e   Diogo Resende   Changes Readme to...
10
  ```sh
b8784def   Diogo Resende   Removes version f...
11
  npm install orm
85017a9e   Diogo Resende   Changes Readme to...
12
13
  ```
  
5b3ffbc1   Diogo Resende   Adds notice about...
14
15
  ## Node.js Version Support
  
f501d2d4   Arek W   Update doco & bum...
16
17
18
19
  Supported: 0.8, 0.10, 0.12, iojs-1.5
  
  Tests are run on [Travis CI](https://travis-ci.org/) for node versions `0.10.x`, `0.12.x` and `iojs-1.5`.
  If you want you can run tests locally:
1e2a6074   Diogo Resende   Updates Readme to...
20
21
  
  ```sh
8fc7dc23   Diogo Resende   Changes Readme te...
22
  npm test
1e2a6074   Diogo Resende   Updates Readme to...
23
  ```
5b3ffbc1   Diogo Resende   Adds notice about...
24
  
06df1cc0   Diogo Resende   Updates Readme to...
25
26
  ## DBMS Support
  
f19449ae   Arek W   Mention MariaDB #486
27
  - MySQL & MariaDB
06df1cc0   Diogo Resende   Updates Readme to...
28
  - PostgreSQL
076728ef   Diogo Resende   Adds mention to A...
29
  - Amazon Redshift
06df1cc0   Diogo Resende   Updates Readme to...
30
  - SQLite
90db723f   Diogo Resende   Updates driver de...
31
  - MongoDB (beta, missing aggregation for now)
06df1cc0   Diogo Resende   Updates Readme to...
32
  
2ef1b3f3   Diogo Resende   Removes roadmap (...
33
34
  ## Features
  
7160fb4a   Diogo Resende   2.0.8
35
  - Create Models, sync, drop, bulk create, get, find, remove, count, aggregated functions
2ef1b3f3   Diogo Resende   Removes roadmap (...
36
  - Create Model associations, find, check, create and remove
c0099049   Diogo Resende   Changes validatio...
37
  - Define custom validations (several builtin validations, check instance properties before saving - see [enforce](http://github.com/dresende/node-enforce) for details)
2c2bc5bd   Nicholas Faiz   change singleton ...
38
  - Model instance caching and integrity (table rows fetched twice are the same object, changes to one change all)
21fd522c   Nicholas Faiz   mention the migra...
39
  - 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)
6bcaa5fc   Diogo Resende   Adds Roadmap to R...
40
  
85017a9e   Diogo Resende   Changes Readme to...
41
42
43
44
  ## Introduction
  
  This is a node.js object relational mapping module.
  
33523e91   Nicholas Faiz   clearer English u...
45
  An example:
85017a9e   Diogo Resende   Changes Readme to...
46
47
  
  ```js
943be48b   Diogo Resende   Adds Settings des...
48
  var orm = require("orm");
85017a9e   Diogo Resende   Changes Readme to...
49
50
  
  orm.connect("mysql://username:password@host/database", function (err, db) {
0bf13e36   Arek W   Update associatio...
51
52
    if (err) throw err;
  
ea3e93d8   Arek W   Bring back tabs
53
54
55
  	var Person = db.define("person", {
  		name      : String,
  		surname   : String,
79e70223   Arek W   Add note about fl...
56
  		age       : Number, // FLOAT
ea3e93d8   Arek W   Bring back tabs
57
58
59
60
61
62
63
64
65
66
67
  		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: {
c0099049   Diogo Resende   Changes validatio...
68
  			age: orm.enforce.ranges.number(18, undefined, "under-age")
ea3e93d8   Arek W   Bring back tabs
69
70
71
  		}
  	});
  
e7cd88d9   Stafford Williams   updated readme ex...
72
      // add the table to the database
fef31883   Arek W   Disable cache by ...
73
  	db.sync(function(err) {
e7cd88d9   Stafford Williams   updated readme ex...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  		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";
  		        });
  		    });
fef31883   Arek W   Disable cache by ...
93
  
ea3e93d8   Arek W   Bring back tabs
94
95
  		});
  	});
85017a9e   Diogo Resende   Changes Readme to...
96
97
98
  });
  ```
  
305b7bcf   Arek W   Mention promise s...
99
100
101
102
103
  ## Promises
  
  You can use the [promise enabled wrapper library](https://github.com/rafaelkaufmann/q-orm).
  
  
bb0ba400   Diogo Resende   Adds initial midd...
104
105
106
107
108
109
110
111
112
113
  ## Express
  
  If you're using Express, you might want to use the simple middleware to integrate more easily.
  
  ```js
  var express = require('express');
  var orm = require('orm');
  var app = express();
  
  app.use(orm.express("mysql://username:password@host/database", {
2f85e307   Diogo Resende   Updates express m...
114
  	define: function (db, models, next) {
ea3e93d8   Arek W   Bring back tabs
115
  		models.person = db.define("person", { ... });
3c0e00c8   Jens Claes   Fixes a bug in th...
116
  		next();
ea3e93d8   Arek W   Bring back tabs
117
  	}
bb0ba400   Diogo Resende   Adds initial midd...
118
119
120
121
  }));
  app.listen(80);
  
  app.get("/", function (req, res) {
ea3e93d8   Arek W   Bring back tabs
122
123
  	// req.models is a reference to models used above in define()
  	req.models.person.find(...);
bb0ba400   Diogo Resende   Adds initial midd...
124
125
126
  });
  ```
  
2e45fd0c   Diogo Resende   Changes Readme or...
127
128
129
  You can call `orm.express` more than once to have multiple database connections. Models defined across connections
  will be joined together in `req.models`. **Don't forget to use it before `app.use(app.router)`, preferably right after your
  assets public folder(s).**
71a5388a   Diogo Resende   Added a note abou...
130
  
6ff996f6   Arek W   Add an example ex...
131
132
133
134
  ## Examples
  
  See `examples/anontxt` for an example express based app.
  
8a57bcf0   Diogo Resende   Removes sections ...
135
  ## Documentation
943be48b   Diogo Resende   Adds Settings des...
136
  
8a57bcf0   Diogo Resende   Removes sections ...
137
  Documentation is moving to the [wiki](https://github.com/dresende/node-orm2/wiki/).
943be48b   Diogo Resende   Adds Settings des...
138
  
8a57bcf0   Diogo Resende   Removes sections ...
139
  ## Settings
e6376bc3   Diogo Resende   Adds a bit of inf...
140
  
8a57bcf0   Diogo Resende   Removes sections ...
141
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Settings).
943be48b   Diogo Resende   Adds Settings des...
142
  
db7f920a   Arek W   Add connection se...
143
144
  ## Connecting
  
8a57bcf0   Diogo Resende   Removes sections ...
145
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Connecting-to-Database).
db7f920a   Arek W   Add connection se...
146
  
85017a9e   Diogo Resende   Changes Readme to...
147
148
  ## Models
  
040dbf02   Diogo Resende   Fixes error in ha...
149
  A 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.
85017a9e   Diogo Resende   Changes Readme to...
150
  
33523e91   Nicholas Faiz   clearer English u...
151
  Models support behaviours for accessing and manipulating table data.
87c49dee   Diogo Resende   Extends Readme.md...
152
  
e82358dc   Diogo Resende   Updates Readme wi...
153
154
  ## Defining Models
  
8a57bcf0   Diogo Resende   Removes sections ...
155
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Defining-Models).
e82358dc   Diogo Resende   Updates Readme wi...
156
  
513d344f   Arek W   Add some property...
157
158
  ### Properties
  
8a57bcf0   Diogo Resende   Removes sections ...
159
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Properties).
513d344f   Arek W   Add some property...
160
  
71e1caac   Arek W   Document model & ...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  ### Instance Methods
  
  Are passed in during model definition.
  
  ```js
  var Person = db.define('person', {
      name    : String,
      surname : String
  }, {
      methods: {
          fullName: function () {
              return this.name + ' ' + this.surname;
          }
      }
  });
  
  Person.get(4, function(err, person) {
      console.log( person.fullName() );
  })
  ```
  
  ### Model Methods
  
  Are defined directly on the model.
  
  ```js
  var Person = db.define('person', {
      name    : String,
44d432b2   Arek W   Add explicit inte...
189
      height  : { type: 'integer' }
71e1caac   Arek W   Document model & ...
190
191
192
193
194
195
196
197
198
  });
  Person.tallerThan = function(height, callback) {
      this.find({ height: orm.gt(height) }, callback);
  };
  
  Person.tallerThan( 192, function(err, tallPeople) { ... } );
  ```
  
  
395406f2   Diogo Resende   Adds db.load() to...
199
200
  ## Loading Models
  
33523e91   Nicholas Faiz   clearer English u...
201
202
203
  Models 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.
  
  Note - using this technique you can have cascading loads.
395406f2   Diogo Resende   Adds db.load() to...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  
  ```js
  // your main file (after connecting)
  db.load("./models", function (err) {
      // loaded!
      var Person = db.models.person;
      var Pet    = db.models.pet;
  });
  
  // models.js
  module.exports = function (db, cb) {
      db.load("./models-extra", function (err) {
          if (err) {
              return cb(err);
          }
  
          db.define('person', {
              name : String
          });
  
          return cb();
      });
  };
  
  // models-extra.js
  module.exports = function (db, cb) {
      db.define('pet', {
          name : String
      });
  
      return cb();
  };
  ```
  
33523e91   Nicholas Faiz   clearer English u...
238
  ## Synchronizing Models
e82358dc   Diogo Resende   Updates Readme wi...
239
  
cab4074d   Jack Wilsdon   Fix invalid wiki ...
240
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Syncing-and-dropping-models).
e82358dc   Diogo Resende   Updates Readme wi...
241
242
243
  
  ## Dropping Models
  
cab4074d   Jack Wilsdon   Fix invalid wiki ...
244
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Syncing-and-dropping-models).
e82358dc   Diogo Resende   Updates Readme wi...
245
  
8ef21248   Diogo Resende   Adds documentatio...
246
247
  ## Advanced Options
  
33523e91   Nicholas Faiz   clearer English u...
248
249
  ORM2 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.
  
7234015d   Arek W   Allow specifying ...
250
251
  For example, each Model instance has a unique ID in the database. This table column is added automatically, and called "id" by default.<br/>
  If you define your own `key: true` column, "id" will not be added:
8ef21248   Diogo Resende   Adds documentatio...
252
253
254
  
  ```js
  var Person = db.define("person", {
7234015d   Arek W   Allow specifying ...
255
256
  	personId : { type: 'serial', key: true },
  	name     : String
8ef21248   Diogo Resende   Adds documentatio...
257
258
  });
  
7234015d   Arek W   Allow specifying ...
259
  // You can also change the default "id" property name globally:
8ef21248   Diogo Resende   Adds documentatio...
260
261
262
263
  db.settings.set("properties.primary_key", "UID");
  
  // ..and then define your Models
  var Pet = db.define("pet", {
ea3e93d8   Arek W   Bring back tabs
264
  	name : String
8ef21248   Diogo Resende   Adds documentatio...
265
266
267
  });
  ```
  
c47db010   Diogo Resende   Adds more informa...
268
269
  **Pet** model will have 2 columns, an `UID` and a `name`.
  
7234015d   Arek W   Allow specifying ...
270
  It's also possible to have composite keys:
1f385197   Benjamin Pannell   Intelligent assoc...
271
272
273
  
  ```js
  var Person = db.define("person", {
2392e383   Axel Christ   Fix type for exte...
274
275
  	firstname : { type: 'text', key: true },
  	lastname  : { type: 'text', key: true }
1f385197   Benjamin Pannell   Intelligent assoc...
276
277
278
  });
  ```
  
c47db010   Diogo Resende   Adds more informa...
279
280
  Other options:
  
fef31883   Arek W   Disable cache by ...
281
  - `cache` : (default: `false`) Set it to `true` to enable Instance cache ([Singletons](#singleton)) or set a timeout value (in seconds);
bf6679a6   Diogo Resende   Adds more documen...
282
283
  - `autoSave` : (default: `false`) Set it to `true` to save an Instance right after changing any property;
  - `autoFetch` : (default: `false`) Set it to `true` to fetch associations when fetching an instance from the database;
67070f03   Diogo Resende   Removes typo from...
284
  - `autoFetchLimit` : (default: `1`) If `autoFetch` is enabled this defines how many hoops (associations of associations)
c47db010   Diogo Resende   Adds more informa...
285
    you want it to automatically fetch.
8ef21248   Diogo Resende   Adds documentatio...
286
  
bf6679a6   Diogo Resende   Adds more documen...
287
288
  ## Hooks
  
8a57bcf0   Diogo Resende   Removes sections ...
289
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Hooks).
da3f23c8   Diogo Resende   Updates Readme to...
290
  
eddd7c54   Diogo Resende   Adds 'Finding Ite...
291
292
  ## Finding Items
  
87c49dee   Diogo Resende   Extends Readme.md...
293
294
295
  ### Model.get(id, [ options ], cb)
  
  To get a specific element from the database use `Model.get`.
eddd7c54   Diogo Resende   Adds 'Finding Ite...
296
297
  
  ```js
87c49dee   Diogo Resende   Extends Readme.md...
298
  Person.get(123, function (err, person) {
ea3e93d8   Arek W   Bring back tabs
299
  	// finds person with id = 123
eddd7c54   Diogo Resende   Adds 'Finding Ite...
300
301
302
  });
  ```
  
87c49dee   Diogo Resende   Extends Readme.md...
303
304
305
  ### Model.find([ conditions ] [, options ] [, limit ] [, order ] [, cb ])
  
  Finding 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).
eddd7c54   Diogo Resende   Adds 'Finding Ite...
306
307
  
  ```js
87c49dee   Diogo Resende   Extends Readme.md...
308
  Person.find({ name: "John", surname: "Doe" }, 3, function (err, people) {
ea3e93d8   Arek W   Bring back tabs
309
  	// finds people with name='John' AND surname='Doe' and returns the first 3
eddd7c54   Diogo Resende   Adds 'Finding Ite...
310
311
312
313
314
315
316
  });
  ```
  
  If you need to sort the results because you're limiting or just because you want them sorted do:
  
  ```js
  Person.find({ surname: "Doe" }, "name", function (err, people) {
ea3e93d8   Arek W   Bring back tabs
317
  	// finds people with surname='Doe' and returns sorted by name ascending
eddd7c54   Diogo Resende   Adds 'Finding Ite...
318
319
  });
  Person.find({ surname: "Doe" }, [ "name", "Z" ], function (err, people) {
ea3e93d8   Arek W   Bring back tabs
320
321
  	// finds people with surname='Doe' and returns sorted by name descending
  	// ('Z' means DESC; 'A' means ASC - default)
eddd7c54   Diogo Resende   Adds 'Finding Ite...
322
323
324
  });
  ```
  
87c49dee   Diogo Resende   Extends Readme.md...
325
  There are more options that you can pass to find something. These options are passed in a second object:
eddd7c54   Diogo Resende   Adds 'Finding Ite...
326
327
328
  
  ```js
  Person.find({ surname: "Doe" }, { offset: 2 }, function (err, people) {
ea3e93d8   Arek W   Bring back tabs
329
  	// finds people with surname='Doe', skips the first 2 and returns the others
eddd7c54   Diogo Resende   Adds 'Finding Ite...
330
331
332
  });
  ```
  
81ae02fd   Arek W   Add where sql doco
333
334
  You can also use raw SQL when searching. It's documented in the *Chaining* section below.
  
e82358dc   Diogo Resende   Updates Readme wi...
335
336
337
  ### Model.count([ conditions, ] cb)
  
  If you just want to count the number of items that match a condition you can just use `.count()` instead of finding all
33523e91   Nicholas Faiz   clearer English u...
338
  of them and counting. This will actually tell the database server to do a count (it won't be done in the node process itself).
e82358dc   Diogo Resende   Updates Readme wi...
339
340
341
  
  ```js
  Person.count({ surname: "Doe" }, function (err, count) {
ea3e93d8   Arek W   Bring back tabs
342
  	console.log("We have %d Does in our db", count);
e82358dc   Diogo Resende   Updates Readme wi...
343
344
345
346
347
348
349
350
351
  });
  ```
  
  ### Model.exists([ conditions, ] cb)
  
  Similar to `.count()`, this method just checks if the count is greater than zero or not.
  
  ```js
  Person.exists({ surname: "Doe" }, function (err, exists) {
ea3e93d8   Arek W   Bring back tabs
352
  	console.log("We %s Does in our db", exists ? "have" : "don't have");
e82358dc   Diogo Resende   Updates Readme wi...
353
354
355
  });
  ```
  
0ed2debe   Diogo Resende   Updates Readme to...
356
357
358
359
360
361
  ### Aggregating Functions
  
  If you need to get some aggregated values from a Model, you can use `Model.aggregate()`. Here's an example to better
  illustrate:
  
  ```js
0e93d119   Diogo Resende   Adds optional sup...
362
  Person.aggregate({ surname: "Doe" }).min("age").max("age").get(function (err, min, max) {
ea3e93d8   Arek W   Bring back tabs
363
  	console.log("The youngest Doe guy has %d years, while the oldest is %d", min, max);
0ed2debe   Diogo Resende   Updates Readme to...
364
365
  });
  ```
a5b0b2c0   Diogo Resende   Adds AggregateFun...
366
367
368
369
370
  
  An `Array` of properties can be passed to select only a few properties. An `Object` is also accepted to define conditions.
  
  Here's an example to illustrate how to use `.groupBy()`:
  
42bb9ac9   huangyingjie   update readme
371
372
373
374
375
376
  ```js
  //The same as "select avg(weight), age from person where country='someCountry' group by age;"
  Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age").get(function (err, stats) {
      // stats is an Array, each item should have 'age' and 'avg_weight'
  });
  ```
0ed2debe   Diogo Resende   Updates Readme to...
377
  
a5b0b2c0   Diogo Resende   Adds AggregateFun...
378
379
380
381
382
383
  ### Base `.aggregate()` methods
  
  - `.limit()`: you can pass a number as a limit, or two numbers as offset and limit respectively
  - `.order()`: same as `Model.find().order()`
  
  ### Additional `.aggregate()` methods
0e93d119   Diogo Resende   Adds optional sup...
384
385
386
387
388
389
390
  
  - `min`
  - `max`
  - `avg`
  - `sum`
  - `count` (there's a shortcut to this - `Model.count`)
  
a5b0b2c0   Diogo Resende   Adds AggregateFun...
391
  There are more aggregate functions depending on the driver (Math functions for example).
87c49dee   Diogo Resende   Extends Readme.md...
392
393
394
  
  #### Chaining
  
33523e91   Nicholas Faiz   clearer English u...
395
  If you prefer less complicated syntax you can chain `.find()` by not giving a callback parameter.
87c49dee   Diogo Resende   Extends Readme.md...
396
  
324dfd52   Diogo Resende   Fixes Readme.md e...
397
  ```js
87c49dee   Diogo Resende   Extends Readme.md...
398
399
400
401
402
  Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "surname").run(function (err, people) {
      // finds people with surname='Doe', skips first 2 and limits to 3 elements,
      // returning only 'name' and 'surname' properties
  });
  ```
5e6c480f   Arek W   Add ChainFind.omit
403
  If you want to skip just one or two properties, you can call `.omit()` instead of `.only`.
eddd7c54   Diogo Resende   Adds 'Finding Ite...
404
  
81ae02fd   Arek W   Add where sql doco
405
406
407
408
409
410
411
412
  Chaining allows for more complicated queries. For example, we can search by specifying custom SQL:
  ```js
  Person.find({ age: 18 }).where("LOWER(surname) LIKE ?", ['dea%']).all( ... );
  ```
  It's bad practice to manually escape SQL parameters as it's error prone and exposes your application to SQL injection.
  The `?` syntax takes care of escaping for you, by safely substituting the question mark in the query with the parameters provided.
  You can also chain multiple `where` clauses as needed.
  
5b9f5d1c   Arek W   Update readme & c...
413
414
415
416
417
418
419
  You can also `order` or `orderRaw`:
  ```js
  Person.find({ age: 18 }).order('-name').all( ... );
  // see the 'Raw queries' section below for more details
  Person.find({ age: 18 }).orderRaw("?? DESC", ['age']).all( ... );
  ```
  
e361be88   Diogo Resende   Adds a few more b...
420
421
422
423
424
425
426
427
  You can also chain and just get the count in the end. In this case, offset, limit and order are ignored.
  
  ```js
  Person.find({ surname: "Doe" }).count(function (err, people) {
      // people = number of people with surname="Doe"
  });
  ```
  
4ebad12d   Diogo Resende   Adds mention to c...
428
  Also available is the option to remove the selected items.
ba1dea53   Arek W   Update chain remo...
429
  Note that a chained remove will not run any hooks.
4ebad12d   Diogo Resende   Adds mention to c...
430
431
432
433
434
435
436
  
  ```js
  Person.find({ surname: "Doe" }).remove(function (err) {
      // Does gone..
  });
  ```
  
90ba9244   Diogo Resende   Adds documentatio...
437
438
439
440
441
  You can also make modifications to your instances using common Array traversal methods and save everything
  in the end.
  
  ```js
  Person.find({ surname: "Doe" }).each(function (person) {
ea3e93d8   Arek W   Bring back tabs
442
  	person.surname = "Dean";
90ba9244   Diogo Resende   Adds documentatio...
443
  }).save(function (err) {
ea3e93d8   Arek W   Bring back tabs
444
  	// done!
90ba9244   Diogo Resende   Adds documentatio...
445
446
447
  });
  
  Person.find({ surname: "Doe" }).each().filter(function (person) {
ea3e93d8   Arek W   Bring back tabs
448
  	return person.age >= 18;
90ba9244   Diogo Resende   Adds documentatio...
449
  }).sort(function (person1, person2) {
ea3e93d8   Arek W   Bring back tabs
450
  	return person1.age < person2.age;
90ba9244   Diogo Resende   Adds documentatio...
451
  }).get(function (people) {
ea3e93d8   Arek W   Bring back tabs
452
  	// get all people with at least 18 years, sorted by age
90ba9244   Diogo Resende   Adds documentatio...
453
454
455
456
457
458
459
  });
  ```
  
  Of course you could do this directly on `.find()`, but for some more complicated tasks this can be very usefull.
  
  `Model.find()` does not return an Array so you can't just chain directly. To start chaining you have to call
  `.each()` (with an optional callback if you want to traverse the list). You can then use the common functions
216907ae   Diogo Resende   Adds more documen...
460
461
462
463
464
465
  `.filter()`, `.sort()` and `.forEach()` more than once.
  
  In the end (or during the process..) you can call:
  - `.count()` if you just want to know how many items there are;
  - `.get()` to retrieve the list;
  - `.save()` to save all item changes.
90ba9244   Diogo Resende   Adds documentatio...
466
  
d22a89b5   Diogo Resende   Updates Readme to...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  #### Conditions
  
  Conditions are defined as an object where every key is a property (table column). All keys are supposed
  to be concatenated by the logical `AND`. Values are considered to match exactly, unless you're passing
  an `Array`. In this case it is considered a list to compare the property with.
  
  ```js
  { col1: 123, col2: "foo" } // `col1` = 123 AND `col2` = 'foo'
  { col1: [ 1, 3, 5 ] } // `col1` IN (1, 3, 5)
  ```
  
  If you need other comparisons, you have to use a special object created by some helper functions. Here are
  a few examples to describe it:
  
  ```js
e361be88   Diogo Resende   Adds a few more b...
482
  { col1: orm.eq(123) } // `col1` = 123 (default)
d22a89b5   Diogo Resende   Updates Readme to...
483
  { col1: orm.ne(123) } // `col1` <> 123
e361be88   Diogo Resende   Adds a few more b...
484
  { col1: orm.gt(123) } // `col1` > 123
d22a89b5   Diogo Resende   Updates Readme to...
485
  { col1: orm.gte(123) } // `col1` >= 123
e361be88   Diogo Resende   Adds a few more b...
486
487
  { col1: orm.lt(123) } // `col1` < 123
  { col1: orm.lte(123) } // `col1` <= 123
d22a89b5   Diogo Resende   Updates Readme to...
488
  { col1: orm.between(123, 456) } // `col1` BETWEEN 123 AND 456
7bdb1a6d   Diogo Resende   Adds not_between(...
489
  { col1: orm.not_between(123, 456) } // `col1` NOT BETWEEN 123 AND 456
2324d34d   Arek W   v2.1.19
490
491
  { col1: orm.like(12 + "%") } // `col1` LIKE '12%'
  { col1: orm.not_like(12 + "%") } // `col1` NOT LIKE '12%'
d0a035f8   Jérémy Lal   Document orm.not_in
492
  { col1: orm.not_in([1, 4, 8]) } // `col1` NOT IN (1, 4, 8)
d22a89b5   Diogo Resende   Updates Readme to...
493
494
  ```
  
556550ed   Arek W   Add custom sql qu...
495
496
  #### Raw queries
  
556550ed   Arek W   Add custom sql qu...
497
498
  ```js
  db.driver.execQuery("SELECT id, email FROM user", function (err, data) { ... })
d5af517c   Arek W   Enable auto-escap...
499
500
  
  // You can escape identifiers and values.
cb34290a   Arek W   Make escaping rea...
501
502
  // For identifier substitution use: ??
  // For value substitution use: ?
d5af517c   Arek W   Enable auto-escap...
503
504
505
506
507
508
509
510
511
512
513
514
  db.driver.execQuery(
    "SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? > ?",
    ['id', 'name', 'name', 'john', 'id', 55],
    function (err, data) { ... }
  )
  
  // Identifiers don't need to be scaped most of the time
  db.driver.execQuery(
    "SELECT user.id, user.name FROM user WHERE user.name LIKE ? AND user.id > ?",
    ['john', 55],
    function (err, data) { ... }
  )
556550ed   Arek W   Add custom sql qu...
515
516
  ```
  
4b85c161   Nicholas Faiz   change singleton ...
517
  ### Caching & Integrity
23e2eec7   Diogo Resende   Adds documentatio...
518
  
fef31883   Arek W   Disable cache by ...
519
  Model instances can be cached (turned off by default). If enabled, multiple different queries will result in the same result - you will
23e2eec7   Diogo Resende   Adds documentatio...
520
  get the same object. If you have other systems that can change your database (or you're developing and need
fef31883   Arek W   Disable cache by ...
521
522
  to make some manual changes) you shouldn't use this feature.
  It can be enabled/disabled per model:
23e2eec7   Diogo Resende   Adds documentatio...
523
524
525
  
  ```js
  var Person = db.define('person', {
ea3e93d8   Arek W   Bring back tabs
526
  	name    : String
23e2eec7   Diogo Resende   Adds documentatio...
527
  }, {
fef31883   Arek W   Disable cache by ...
528
  	cache   : true
23e2eec7   Diogo Resende   Adds documentatio...
529
530
  });
  ```
7a9b766a   Diogo Resende   Lints some missin...
531
  
54f272fb   Arek W   Better describe h...
532
  and also globally:
7a9b766a   Diogo Resende   Lints some missin...
533
  
54f272fb   Arek W   Better describe h...
534
535
  ```js
  orm.connect('...', function(err, db) {
fef31883   Arek W   Disable cache by ...
536
    db.settings.set('instance.cache', true);
54f272fb   Arek W   Better describe h...
537
538
  });
  ```
23e2eec7   Diogo Resende   Adds documentatio...
539
  
33523e91   Nicholas Faiz   clearer English u...
540
  The cache can be configured to expire after a period of time by passing in a number instead of a
c96d08b1   Diogo Resende   Updates documenta...
541
542
  boolean. The number will be considered the cache timeout in seconds (you can use floating point).
  
5c5c8c2f   Diogo Resende   Adds small note a...
543
544
545
  **Note**: One exception about Caching is that it won't be used if an instance is not saved. For example, if
  you fetch a Person and then change it, while it doesn't get saved it won't be passed from Cache.
  
47565d66   Aleksandr Palamar   Added "Creating I...
546
547
548
549
550
551
552
553
  ## Creating Items
  
  ### Model.create(items, cb)
  
  To insert new elements to the database use `Model.create`.
  
  ```js
  Person.create([
ea3e93d8   Arek W   Bring back tabs
554
555
556
557
558
559
560
561
562
563
564
565
  	{
  		name: "John",
  		surname: "Doe",
  		age: 25,
  		male: true
  	},
  	{
  		name: "Liza",
  		surname: "Kollan",
  		age: 19,
  		male: false
  	}
a570fec0   Aleksandr Palamar   Some corrections ...
566
  ], function (err, items) {
ea3e93d8   Arek W   Bring back tabs
567
568
  	// err - description of the error or null
  	// items - array of inserted items
47565d66   Aleksandr Palamar   Added "Creating I...
569
570
571
  });
  ```
  
a40bc380   Diogo Resende   Adds "Validations...
572
  ## Updating Items
5b46f824   Diogo Resende   Updates Readme wi...
573
574
575
576
577
578
  
  Every item returned has the properties that were defined to the Model and also a couple of methods you can
  use to change each item.
  
  ```js
  Person.get(1, function (err, John) {
ea3e93d8   Arek W   Bring back tabs
579
580
581
582
583
  	John.name = "Joe";
  	John.surname = "Doe";
  	John.save(function (err) {
  		console.log("saved!");
  	});
5b46f824   Diogo Resende   Updates Readme wi...
584
585
586
587
588
589
590
  });
  ```
  
  Updating and then saving an instance can be done in a single call:
  
  ```js
  Person.get(1, function (err, John) {
ea3e93d8   Arek W   Bring back tabs
591
592
593
  	John.save({ name: "Joe", surname: "Doe" }, function (err) {
  		console.log("saved!");
  	});
5b46f824   Diogo Resende   Updates Readme wi...
594
595
596
597
598
599
600
601
  });
  ```
  
  If you want to remove an instance, just do:
  
  ```js
  // you could do this without even fetching it, look at Chaining section above
  Person.get(1, function (err, John) {
ea3e93d8   Arek W   Bring back tabs
602
603
604
  	John.remove(function (err) {
  		console.log("removed!");
  	});
5b46f824   Diogo Resende   Updates Readme wi...
605
606
607
  });
  ```
  
a40bc380   Diogo Resende   Adds "Validations...
608
609
  ## Validations
  
8a57bcf0   Diogo Resende   Removes sections ...
610
  See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Validations).
a40bc380   Diogo Resende   Adds "Validations...
611
  
85017a9e   Diogo Resende   Changes Readme to...
612
613
614
615
  ## Associations
  
  An association is a relation between one or more tables.
  
0bf13e36   Arek W   Update associatio...
616
  ### hasOne
7a9b766a   Diogo Resende   Lints some missin...
617
  
0bf13e36   Arek W   Update associatio...
618
619
620
621
622
623
624
625
626
627
628
629
630
  Is a **many to one** relationship. It's the same as **belongs to.**<br/>
  Eg: `Animal.hasOne('owner', Person)`.<br/>
  Animal can only have one owner, but Person can have many animals.<br/>
  Animal will have the `owner_id` property automatically added.
  
  The following functions will become available:
  ```js
  animal.getOwner(function..)         // Gets owner
  animal.setOwner(person, function..) // Sets owner_id
  animal.hasOwner(function..)         // Checks if owner exists
  animal.removeOwner()                // Sets owner_id to 0
  ```
  
5263d36f   Tape   Document the find...
631
632
633
634
635
636
637
638
  **Chain Find**
  
  The hasOne association is also chain find compatible. Using the example above, we can do this to access a new instance of a ChainFind object:
  
  ```js
  Animal.findByOwner({ /* options */ })
  ```
  
0bf13e36   Arek W   Update associatio...
639
  **Reverse access**
7a9b766a   Diogo Resende   Lints some missin...
640
  
0bf13e36   Arek W   Update associatio...
641
642
643
  ```js
  Animal.hasOne('owner', Person, {reverse: 'pets'})
  ```
7a9b766a   Diogo Resende   Lints some missin...
644
  
0bf13e36   Arek W   Update associatio...
645
  will add the following:
7a9b766a   Diogo Resende   Lints some missin...
646
  
0bf13e36   Arek W   Update associatio...
647
  ```js
5263d36f   Tape   Document the find...
648
  // Instance methods
0bf13e36   Arek W   Update associatio...
649
650
  person.getPets(function..)
  person.setPets(cat, function..)
5263d36f   Tape   Document the find...
651
652
653
  
  // Model methods
  Person.findByPets({ /* options */ }) // returns ChainFind object
0bf13e36   Arek W   Update associatio...
654
655
  ```
  
0bf13e36   Arek W   Update associatio...
656
  ### hasMany
7a9b766a   Diogo Resende   Lints some missin...
657
  
0bf13e36   Arek W   Update associatio...
658
  Is a **many to many** relationship (includes join table).<br/>
d3344648   Arek W   Doco about `key: ...
659
  Eg: `Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients', key: true })`.<br/>
0bf13e36   Arek W   Update associatio...
660
  Patient can have many different doctors. Each doctor can have many different patients.
1bc4ca2d   Diogo Resende   Adds more documen...
661
  
0bf13e36   Arek W   Update associatio...
662
  This will create a join table `patient_doctors` when you call `Patient.sync()`:
85017a9e   Diogo Resende   Changes Readme to...
663
  
0bf13e36   Arek W   Update associatio...
664
665
   column name | type
   :-----------|:--------
d3344648   Arek W   Doco about `key: ...
666
667
   patient_id  | Integer (composite key)
   doctor_id   | Integer (composite key)
0bf13e36   Arek W   Update associatio...
668
669
670
   why         | varchar(255)
  
  The following functions will be available:
7a9b766a   Diogo Resende   Lints some missin...
671
  
0bf13e36   Arek W   Update associatio...
672
673
674
675
676
677
678
679
680
  ```js
  patient.getDoctors(function..)           // List of doctors
  patient.addDoctors(docs, function...)    // Adds entries to join table
  patient.setDoctors(docs, function...)    // Removes existing entries in join table, adds new ones
  patient.hasDoctors(docs, function...)    // Checks if patient is associated to specified doctors
  patient.removeDoctors(docs, function...) // Removes specified doctors from join table
  
  doctor.getPatients(function..)
  etc...
3d1d026c   Arek W   Don't auto save a...
681
682
683
684
  
  // You can also do:
  patient.doctors = [doc1, doc2];
  patient.save(...)
0bf13e36   Arek W   Update associatio...
685
686
687
  ```
  
  To associate a doctor to a patient:
7a9b766a   Diogo Resende   Lints some missin...
688
  
0bf13e36   Arek W   Update associatio...
689
690
691
  ```js
  patient.addDoctor(surgeon, {why: "remove appendix"}, function(err) { ... } )
  ```
7a9b766a   Diogo Resende   Lints some missin...
692
  
0bf13e36   Arek W   Update associatio...
693
694
  which will add `{patient_id: 4, doctor_id: 6, why: "remove appendix"}` to the join table.
  
b3d5343b   Diogo Resende   Adds an example a...
695
696
697
698
699
700
701
702
703
704
705
  #### getAccessor
  
  This accessor in this type of association returns a `ChainFind` if not passing a callback. This means you can
  do things like:
  
  ```js
  patient.getDoctors().order("name").offset(1).run(function (err, doctors), {
  	// ... all doctors, ordered by name, excluding first one
  });
  ```
  
7a9b766a   Diogo Resende   Lints some missin...
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
  ### extendsTo
  
  If you want to split maybe optional properties into different tables or collections. Every extension will be in a new table,
  where the unique identifier of each row is the main model instance id. For example:
  
  ```js
  var Person = db.define("person", {
      name : String
  });
  var PersonAddress = Person.extendsTo("address", {
      street : String,
      number : Number
  });
  ```
  
  This will create a table `person` with columns `id` and `name`. The extension will create a table `person_address` with
  columns `person_id`, `street` and `number`. The methods available in the `Person` model are similar to an `hasOne`
  association. In this example you would be able to call `.getAddress(cb)`, `.setAddress(Address, cb)`, ..
  
96ae4301   Diogo Resende   Adds note to Mode...
725
726
727
728
  **Note:** you don't have to save the result from `Person.extendsTo`. It returns an extended model. You can use it to query
  directly this extended table (and even find the related model) but that's up to you. If you only want to access it using the
  original model you can just discard the return.
  
0bf13e36   Arek W   Update associatio...
729
730
731
  ### Examples & options
  
  If you have a relation of 1 to n, you should use `hasOne` (belongs to) association.
85017a9e   Diogo Resende   Changes Readme to...
732
733
734
  
  ```js
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
735
      name : String
85017a9e   Diogo Resende   Changes Readme to...
736
737
  });
  var Animal = db.define('animal', {
0bf13e36   Arek W   Update associatio...
738
      name : String
85017a9e   Diogo Resende   Changes Readme to...
739
  });
0bf13e36   Arek W   Update associatio...
740
  Animal.hasOne("owner", Person); // creates column 'owner_id' in 'animal' table
85017a9e   Diogo Resende   Changes Readme to...
741
742
  
  // get animal with id = 123
0bf13e36   Arek W   Update associatio...
743
744
  Animal.get(123, function (err, animal) {
      // animal is the animal model instance, if found
3c8cc19d   Benjamin Nortier   Fix typo in READM...
745
      animal.getOwner(function (err, person) {
0bf13e36   Arek W   Update associatio...
746
747
          // if animal has really an owner, person points to it
      });
85017a9e   Diogo Resende   Changes Readme to...
748
749
750
  });
  ```
  
77914399   Arek W   Reflect default h...
751
  You can mark the `owner_id` field as required in the database by specifying the `required` option:
86405188   Arek W   Adds 'required' o...
752
  ```js
77914399   Arek W   Reflect default h...
753
  Animal.hasOne("owner", Person, { required: true });
86405188   Arek W   Adds 'required' o...
754
755
  ```
  
ce7de55c   justinTNT   add alwaysValidat...
756
757
758
759
760
761
  If a field is not required, but should be validated even if it is not present, then specify the `alwaysValidate` option.
  (this can happen, for example when validation of a null field depends on other fields in the record)
  ```js
  Animal.hasOne("owner", Person, { required: false, alwaysValidate: true });
  ```
  
1bc4ca2d   Diogo Resende   Adds more documen...
762
763
764
  If you prefer to use another name for the field (owner_id) you can change this parameter in the settings.
  
  ```js
1f385197   Benjamin Pannell   Intelligent assoc...
765
  db.settings.set("properties.association_key", "{field}_{name}"); // {name} will be replaced by 'owner' and {field} will be replaced by 'id' in this case
1bc4ca2d   Diogo Resende   Adds more documen...
766
767
  ```
  
0bf13e36   Arek W   Update associatio...
768
  **Note: This has to be done before the association is specified.**
1bc4ca2d   Diogo Resende   Adds more documen...
769
  
0bf13e36   Arek W   Update associatio...
770
  The `hasMany` associations can have additional properties in the association table.
85017a9e   Diogo Resende   Changes Readme to...
771
772
773
  
  ```js
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
774
      name : String
1f3d017e   Diogo Resende   Fixes Readme exam...
775
776
777
  });
  Person.hasMany("friends", {
      rate : Number
d3344648   Arek W   Doco about `key: ...
778
  }, {}, { key: true });
1f3d017e   Diogo Resende   Fixes Readme exam...
779
780
  
  Person.get(123, function (err, John) {
0bf13e36   Arek W   Update associatio...
781
782
783
784
      John.getFriends(function (err, friends) {
          // assumes rate is another column on table person_friends
          // you can access it by going to friends[N].extra.rate
      });
1f3d017e   Diogo Resende   Fixes Readme exam...
785
786
787
  });
  ```
  
0bf13e36   Arek W   Update associatio...
788
789
  If you prefer you can activate `autoFetch`.
  This way associations are automatically fetched when you get or find instances of a model.
1f3d017e   Diogo Resende   Fixes Readme exam...
790
791
792
  
  ```js
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
793
    name : String
1f3d017e   Diogo Resende   Fixes Readme exam...
794
795
796
797
  });
  Person.hasMany("friends", {
      rate : Number
  }, {
d3344648   Arek W   Doco about `key: ...
798
      key       : true, // Turns the foreign keys in the join table into a composite key
1f3d017e   Diogo Resende   Fixes Readme exam...
799
800
801
802
803
804
805
806
807
808
809
810
      autoFetch : true
  });
  
  Person.get(123, function (err, John) {
      // no need to do John.getFriends() , John already has John.friends Array
  });
  ```
  
  You can also define this option globally instead of a per association basis.
  
  ```js
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
811
      name : String
1f3d017e   Diogo Resende   Fixes Readme exam...
812
813
814
815
816
  }, {
      autoFetch : true
  });
  Person.hasMany("friends", {
      rate : Number
d3344648   Arek W   Doco about `key: ...
817
818
  }, {
    key: true
1f3d017e   Diogo Resende   Fixes Readme exam...
819
  });
d22a89b5   Diogo Resende   Updates Readme to...
820
  ```
2a84a146   Diogo Resende   Adds documentatio...
821
  
1bc4ca2d   Diogo Resende   Adds more documen...
822
823
824
  Associations can make calls to the associated Model by using the `reverse` option. For example, if you have an
  association from ModelA to ModelB, you can create an accessor in ModelB to get instances from ModelA.
  Confusing? Look at the next example.
2a84a146   Diogo Resende   Adds documentatio...
825
826
827
  
  ```js
  var Pet = db.define('pet', {
0bf13e36   Arek W   Update associatio...
828
      name : String
2a84a146   Diogo Resende   Adds documentatio...
829
830
  });
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
831
      name : String
2a84a146   Diogo Resende   Adds documentatio...
832
833
  });
  Pet.hasOne("owner", Person, {
0bf13e36   Arek W   Update associatio...
834
      reverse : "pets"
2a84a146   Diogo Resende   Adds documentatio...
835
836
837
  });
  
  Person(4).getPets(function (err, pets) {
0bf13e36   Arek W   Update associatio...
838
839
840
841
842
      // 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
2a84a146   Diogo Resende   Adds documentatio...
843
844
  });
  ```
1bc4ca2d   Diogo Resende   Adds more documen...
845
  
0bf13e36   Arek W   Update associatio...
846
847
  This makes even more sense when having `hasMany` associations since you can manage the *many to many*
  associations from both sides.
1bc4ca2d   Diogo Resende   Adds more documen...
848
849
850
  
  ```js
  var Pet = db.define('pet', {
0bf13e36   Arek W   Update associatio...
851
      name : String
1bc4ca2d   Diogo Resende   Adds more documen...
852
853
  });
  var Person = db.define('person', {
0bf13e36   Arek W   Update associatio...
854
      name : String
1bc4ca2d   Diogo Resende   Adds more documen...
855
  });
040dbf02   Diogo Resende   Fixes error in ha...
856
  Person.hasMany("pets", Pet, {
1bc4ca2d   Diogo Resende   Adds more documen...
857
858
      bought  : Date
  }, {
d3344648   Arek W   Doco about `key: ...
859
      key     : true,
0bf13e36   Arek W   Update associatio...
860
      reverse : "owners"
1bc4ca2d   Diogo Resende   Adds more documen...
861
862
863
864
865
  });
  
  Person(1).getPets(...);
  Pet(2).getOwners(...);
  ```
44ea4644   DullReferenceException   Enabling third-pa...
866
  
33a09e9b   DullReferenceException   Terminology chang...
867
  ## Adding external database adapters
44ea4644   DullReferenceException   Enabling third-pa...
868
  
2324d34d   Arek W   v2.1.19
869
  To add an external database adapter to `orm`, call the `addAdapter` method, passing in the alias to use for connecting
33a09e9b   DullReferenceException   Terminology chang...
870
  with this adapter, along with the constructor for the adapter:
44ea4644   DullReferenceException   Enabling third-pa...
871
872
  
  ```js
33a09e9b   DullReferenceException   Terminology chang...
873
  require('orm').addAdapter('cassandra', CassandraAdapter);
44ea4644   DullReferenceException   Enabling third-pa...
874
875
  ```
  
33a09e9b   DullReferenceException   Terminology chang...
876
  See [the documentation for creating adapters](./Adapters.md) for more details.