프로젝트

일반

사용자정보

통계
| 개정판:

root / HServer / 00.Server / 00.Program / node_modules / mquery / README.md

이력 | 보기 | 이력해설 | 다운로드 (31 KB)

1
# mquery
2

    
3
`mquery` is a fluent mongodb query builder designed to run in multiple environments.
4

    
5
## Features
6

    
7
  - fluent query builder api
8
  - custom base query support
9
  - MongoDB 2.4 geoJSON support
10
  - method + option combinations validation
11
  - node.js driver compatibility
12
  - environment detection
13
  - [debug](https://github.com/visionmedia/debug) support
14
  - separated collection implementations for maximum flexibility
15

    
16
[![Build Status](https://travis-ci.org/aheckmann/mquery.png)](https://travis-ci.org/aheckmann/mquery)
17

    
18
## Use
19

    
20
```js
21
require('mongodb').connect(uri, function (err, db) {
22
  if (err) return handleError(err);
23

    
24
  // get a collection
25
  var collection = db.collection('artists');
26

    
27
  // pass it to the constructor
28
  mquery(collection).find({..}, callback);
29

    
30
  // or pass it to the collection method
31
  mquery().find({..}).collection(collection).exec(callback)
32

    
33
  // or better yet, create a custom query constructor that has it always set
34
  var Artist = mquery(collection).toConstructor();
35
  Artist().find(..).where(..).exec(callback)
36
})
37
```
38

    
39
`mquery` requires a collection object to work with. In the example above we just pass the collection object created using the official [MongoDB driver](https://github.com/mongodb/node-mongodb-native).
40

    
41

    
42
## Fluent API
43

    
44
- [find](#find)
45
- [findOne](#findOne)
46
- [count](#count)
47
- [remove](#remove)
48
- [update](#update)
49
- [findOneAndUpdate](#findoneandupdate)
50
- [findOneAndRemove](#findoneandremove)
51
- [distinct](#distinct)
52
- [exec](#exec)
53
- [stream](#stream)
54
- [all](#all)
55
- [and](#and)
56
- [box](#box)
57
- [circle](#circle)
58
- [elemMatch](#elemmatch)
59
- [equals](#equals)
60
- [exists](#exists)
61
- [geometry](#geometry)
62
- [gt](#gt)
63
- [gte](#gte)
64
- [in](#in)
65
- [intersects](#intersects)
66
- [lt](#lt)
67
- [lte](#lte)
68
- [maxDistance](#maxdistance)
69
- [mod](#mod)
70
- [ne](#ne)
71
- [nin](#nin)
72
- [nor](#nor)
73
- [near](#near)
74
- [or](#or)
75
- [polygon](#polygon)
76
- [regex](#regex)
77
- [select](#select)
78
- [selected](#selected)
79
- [selectedInclusively](#selectedinclusively)
80
- [selectedExclusively](#selectedexclusively)
81
- [size](#size)
82
- [slice](#slice)
83
- [within](#within)
84
- [where](#where)
85
- [$where](#where-1)
86
- [batchSize](#batchsize)
87
- [comment](#comment)
88
- [hint](#hint)
89
- [limit](#limit)
90
- [maxScan](#maxscan)
91
- [maxTime](#maxtime)
92
- [skip](#skip)
93
- [sort](#sort)
94
- [read](#read)
95
- [slaveOk](#slaveok)
96
- [snapshot](#snapshot)
97
- [tailable](#tailable)
98

    
99
## Helpers
100

    
101
- [collection](#collection)
102
- [then](#then)
103
- [thunk](#thunk)
104
- [merge](#mergeobject)
105
- [setOptions](#setoptionsoptions)
106
- [setTraceFunction](#settracefunctionfunc)
107
- [mquery.setGlobalTraceFunction](#mquerysetglobaltracefunctionfunc)
108
- [mquery.canMerge](#mquerycanmerge)
109
- [mquery.use$geoWithin](#mqueryusegeowithin)
110

    
111
### find()
112

    
113
Declares this query a _find_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
114

    
115
```js
116
mquery().find()
117
mquery().find(match)
118
mquery().find(callback)
119
mquery().find(match, function (err, docs) {
120
  assert(Array.isArray(docs));
121
})
122
```
123

    
124
### findOne()
125

    
126
Declares this query a _findOne_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
127

    
128
```js
129
mquery().findOne()
130
mquery().findOne(match)
131
mquery().findOne(callback)
132
mquery().findOne(match, function (err, doc) {
133
  if (doc) {
134
    // the document may not be found
135
    console.log(doc);
136
  }
137
})
138
```
139

    
140
### count()
141

    
142
Declares this query a _count_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
143

    
144
```js
145
mquery().count()
146
mquery().count(match)
147
mquery().count(callback)
148
mquery().count(match, function (err, number){
149
  console.log('we found %d matching documents', number);
150
})
151
```
152

    
153
### remove()
154

    
155
Declares this query a _remove_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
156

    
157
```js
158
mquery().remove()
159
mquery().remove(match)
160
mquery().remove(callback)
161
mquery().remove(match, function (err){})
162
```
163

    
164
### update()
165

    
166
Declares this query an _update_ query. Optionally pass an update document, match clause, options or callback. If a callback is passed, the query is executed. To force execution without passing a callback, run `update(true)`.
167

    
168
```js
169
mquery().update()
170
mquery().update(match, updateDocument)
171
mquery().update(match, updateDocument, options)
172

    
173
// the following all execute the command
174
mquery().update(callback)
175
mquery().update({$set: updateDocument, callback)
176
mquery().update(match, updateDocument, callback)
177
mquery().update(match, updateDocument, options, function (err, result){})
178
mquery().update(true) // executes (unsafe write)
179
```
180

    
181
##### the update document
182

    
183
All paths passed that are not `$atomic` operations will become `$set` ops. For example:
184

    
185
```js
186
mquery(collection).where({ _id: id }).update({ title: 'words' }, callback)
187
```
188

    
189
becomes
190

    
191
```js
192
collection.update({ _id: id }, { $set: { title: 'words' }}, callback)
193
```
194

    
195
This behavior can be overridden using the `overwrite` option (see below).
196

    
197
##### options
198

    
199
Options are passed to the `setOptions()` method.
200

    
201
- overwrite
202

    
203
Passing an empty object `{ }` as the update document will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option, the update operation will be ignored and the callback executed without sending the command to MongoDB to prevent accidently overwritting documents in the collection.
204

    
205
```js
206
var q = mquery(collection).where({ _id: id }).setOptions({ overwrite: true });
207
q.update({ }, callback); // overwrite with an empty doc
208
```
209

    
210
The `overwrite` option isn't just for empty objects, it also provides a means to override the default `$set` conversion and send the update document as is.
211

    
212
```js
213
// create a base query
214
var base = mquery({ _id: 108 }).collection(collection).toConstructor();
215

    
216
base().findOne(function (err, doc) {
217
  console.log(doc); // { _id: 108, name: 'cajon' })
218

    
219
  base().setOptions({ overwrite: true }).update({ changed: true }, function (err) {
220
    base.findOne(function (err, doc) {
221
      console.log(doc); // { _id: 108, changed: true }) - the doc was overwritten
222
    });
223
  });
224
})
225
```
226

    
227
- multi
228

    
229
Updates only modify a single document by default. To update multiple documents, set the `multi` option to `true`.
230

    
231
```js
232
mquery()
233
  .collection(coll)
234
  .update({ name: /^match/ }, { $addToSet: { arr: 4 }}, { multi: true }, callback)
235

    
236
// another way of doing it
237
mquery({ name: /^match/ })
238
  .collection(coll)
239
  .setOptions({ multi: true })
240
  .update({ $addToSet: { arr: 4 }}, callback)
241

    
242
// update multiple documents with an empty doc
243
var q = mquery(collection).where({ name: /^match/ });
244
q.setOptions({ multi: true, overwrite: true })
245
q.update({ });
246
q.update(function (err, result) {
247
  console.log(arguments);
248
});
249
```
250

    
251
### findOneAndUpdate()
252

    
253
Declares this query a _findAndModify_ with update query. Optionally pass a match clause, update document, options, or callback. If a callback is passed, the query is executed.
254

    
255
When executed, the first matching document (if found) is modified according to the update document and passed back to the callback.
256

    
257
##### options
258

    
259
Options are passed to the `setOptions()` method.
260

    
261
- `new`: boolean - true to return the modified document rather than the original. defaults to true
262
- `upsert`: boolean - creates the object if it doesn't exist. defaults to false
263
- `sort`: if multiple docs are found by the match condition, sets the sort order to choose which doc to update
264

    
265
```js
266
query.findOneAndUpdate()
267
query.findOneAndUpdate(updateDocument)
268
query.findOneAndUpdate(match, updateDocument)
269
query.findOneAndUpdate(match, updateDocument, options)
270

    
271
// the following all execute the command
272
query.findOneAndUpdate(callback)
273
query.findOneAndUpdate(updateDocument, callback)
274
query.findOneAndUpdate(match, updateDocument, callback)
275
query.findOneAndUpdate(match, updateDocument, options, function (err, doc) {
276
  if (doc) {
277
    // the document may not be found
278
    console.log(doc);
279
  }
280
})
281
 ```
282

    
283
### findOneAndRemove()
284

    
285
Declares this query a _findAndModify_ with remove query. Optionally pass a match clause, options, or callback. If a callback is passed, the query is executed.
286

    
287
When executed, the first matching document (if found) is modified according to the update document, removed from the collection and passed to the callback.
288

    
289
##### options
290

    
291
Options are passed to the `setOptions()` method.
292

    
293
- `sort`: if multiple docs are found by the condition, sets the sort order to choose which doc to modify and remove
294

    
295
```js
296
A.where().findOneAndRemove()
297
A.where().findOneAndRemove(match)
298
A.where().findOneAndRemove(match, options)
299

    
300
// the following all execute the command
301
A.where().findOneAndRemove(callback)
302
A.where().findOneAndRemove(match, callback)
303
A.where().findOneAndRemove(match, options, function (err, doc) {
304
  if (doc) {
305
    // the document may not be found
306
    console.log(doc);
307
  }
308
})
309
 ```
310

    
311
### distinct()
312

    
313
Declares this query a _distinct_ query. Optionally pass the distinct field, a match clause or callback. If a callback is passed the query is executed.
314

    
315
```js
316
mquery().distinct()
317
mquery().distinct(match)
318
mquery().distinct(match, field)
319
mquery().distinct(field)
320

    
321
// the following all execute the command
322
mquery().distinct(callback)
323
mquery().distinct(field, callback)
324
mquery().distinct(match, callback)
325
mquery().distinct(match, field, function (err, result) {
326
  console.log(result);
327
})
328
```
329

    
330
### exec()
331

    
332
Executes the query.
333

    
334
```js
335
mquery().findOne().where('route').intersects(polygon).exec(function (err, docs){})
336
```
337

    
338
### stream()
339

    
340
Executes the query and returns a stream.
341

    
342
```js
343
var stream = mquery().find().stream(options);
344
stream.on('data', cb);
345
stream.on('close', fn);
346
```
347

    
348
Note: this only works with `find()` operations.
349

    
350
Note: returns the stream object directly from the node-mongodb-native driver. (currently streams1 type stream). Any options will be passed along to the [driver method](http://mongodb.github.io/node-mongodb-native/api-generated/cursor.html#stream).
351

    
352
-------------
353

    
354
### all()
355

    
356
Specifies an `$all` query condition
357

    
358
```js
359
mquery().where('permission').all(['read', 'write'])
360
```
361

    
362
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/all/)
363

    
364
### and()
365

    
366
Specifies arguments for an `$and` condition
367

    
368
```js
369
mquery().and([{ color: 'green' }, { status: 'ok' }])
370
```
371

    
372
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/and/)
373

    
374
### box()
375

    
376
Specifies a `$box` condition
377

    
378
```js
379
var lowerLeft = [40.73083, -73.99756]
380
var upperRight= [40.741404,  -73.988135]
381

    
382
mquery().where('location').within().box(lowerLeft, upperRight)
383
```
384

    
385
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/box/)
386

    
387
### circle()
388

    
389
Specifies a `$center` or `$centerSphere` condition.
390

    
391
```js
392
var area = { center: [50, 50], radius: 10, unique: true }
393
query.where('loc').within().circle(area)
394
query.circle('loc', area);
395

    
396
// for spherical calculations
397
var area = { center: [50, 50], radius: 10, unique: true, spherical: true }
398
query.where('loc').within().circle(area)
399
query.circle('loc', area);
400
```
401

    
402
- [MongoDB Documentation - center](http://docs.mongodb.org/manual/reference/operator/center/)
403
- [MongoDB Documentation - centerSphere](http://docs.mongodb.org/manual/reference/operator/centerSphere/)
404

    
405
### elemMatch()
406

    
407
Specifies an `$elemMatch` condition
408

    
409
```js
410
query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})
411

    
412
query.elemMatch('comment', function (elem) {
413
  elem.where('author').equals('autobot');
414
  elem.where('votes').gte(5);
415
})
416
```
417

    
418
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/elemMatch/)
419

    
420
### equals()
421

    
422
Specifies the complementary comparison value for the path specified with `where()`.
423

    
424
```js
425
mquery().where('age').equals(49);
426

    
427
// is the same as
428

    
429
mquery().where({ 'age': 49 });
430
```
431

    
432
### exists()
433

    
434
Specifies an `$exists` condition
435

    
436
```js
437
// { name: { $exists: true }}
438
mquery().where('name').exists()
439
mquery().where('name').exists(true)
440
mquery().exists('name')
441

    
442
// { name: { $exists: false }}
443
mquery().where('name').exists(false);
444
mquery().exists('name', false);
445
```
446

    
447
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/exists/)
448

    
449
### geometry()
450

    
451
Specifies a `$geometry` condition
452

    
453
```js
454
var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
455
query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
456

    
457
// or
458
var polyB = [[ 0, 0 ], [ 1, 1 ]]
459
query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
460

    
461
// or
462
var polyC = [ 0, 0 ]
463
query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
464

    
465
// or
466
query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
467

    
468
// or
469
query.where('loc').near().geometry({ type: 'Point', coordinates: [3,5] })
470
```
471

    
472
`geometry()` **must** come after `intersects()`, `within()`, or `near()`.
473

    
474
The `object` argument must contain `type` and `coordinates` properties.
475

    
476
- type `String`
477
- coordinates `Array`
478

    
479
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geometry/)
480

    
481
### gt()
482

    
483
Specifies a `$gt` query condition.
484

    
485
```js
486
mquery().where('clicks').gt(999)
487
```
488

    
489
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gt/)
490

    
491
### gte()
492

    
493
Specifies a `$gte` query condition.
494

    
495
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gte/)
496

    
497
```js
498
mquery().where('clicks').gte(1000)
499
```
500

    
501
### in()
502

    
503
Specifies an `$in` query condition.
504

    
505
```js
506
mquery().where('author_id').in([3, 48901, 761])
507
```
508

    
509
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/in/)
510

    
511
### intersects()
512

    
513
Declares an `$geoIntersects` query for `geometry()`.
514

    
515
```js
516
query.where('path').intersects().geometry({
517
    type: 'LineString'
518
  , coordinates: [[180.0, 11.0], [180, 9.0]]
519
})
520

    
521
// geometry arguments are supported
522
query.where('path').intersects({
523
    type: 'LineString'
524
  , coordinates: [[180.0, 11.0], [180, 9.0]]
525
})
526
```
527

    
528
**Must** be used after `where()`.
529

    
530
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoIntersects/)
531

    
532
### lt()
533

    
534
Specifies a `$lt` query condition.
535

    
536
```js
537
mquery().where('clicks').lt(50)
538
```
539

    
540
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lt/)
541

    
542
### lte()
543

    
544
Specifies a `$lte` query condition.
545

    
546
```js
547
mquery().where('clicks').lte(49)
548
```
549

    
550
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lte/)
551

    
552
### maxDistance()
553

    
554
Specifies a `$maxDistance` query condition.
555

    
556
```js
557
mquery().where('location').near({ center: [139, 74.3] }).maxDistance(5)
558
```
559

    
560
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/maxDistance/)
561

    
562
### mod()
563

    
564
Specifies a `$mod` condition
565

    
566
```js
567
mquery().where('count').mod(2, 0)
568
```
569

    
570
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/mod/)
571

    
572
### ne()
573

    
574
Specifies a `$ne` query condition.
575

    
576
```js
577
mquery().where('status').ne('ok')
578
```
579

    
580
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/ne/)
581

    
582
### nin()
583

    
584
Specifies an `$nin` query condition.
585

    
586
```js
587
mquery().where('author_id').nin([3, 48901, 761])
588
```
589

    
590
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nin/)
591

    
592
### nor()
593

    
594
Specifies arguments for an `$nor` condition.
595

    
596
```js
597
mquery().nor([{ color: 'green' }, { status: 'ok' }])
598
```
599

    
600
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nor/)
601

    
602
### near()
603

    
604
Specifies arguments for a `$near` or `$nearSphere` condition.
605

    
606
These operators return documents sorted by distance.
607

    
608
#### Example
609

    
610
```js
611
query.where('loc').near({ center: [10, 10] });
612
query.where('loc').near({ center: [10, 10], maxDistance: 5 });
613
query.near('loc', { center: [10, 10], maxDistance: 5 });
614

    
615
// GeoJSON
616
query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }});
617
query.where('loc').near({ center: { type: 'Point', coordinates: [10, 10] }, maxDistance: 5, spherical: true });
618
query.where('loc').near().geometry({ type: 'Point', coordinates: [10, 10] });
619

    
620
// For a $nearSphere condition, pass the `spherical` option.
621
query.near({ center: [10, 10], maxDistance: 5, spherical: true });
622
```
623

    
624
[MongoDB Documentation](http://www.mongodb.org/display/DOCS/Geospatial+Indexing)
625

    
626
### or()
627

    
628
Specifies arguments for an `$or` condition.
629

    
630
```js
631
mquery().or([{ color: 'red' }, { status: 'emergency' }])
632
```
633

    
634
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/or/)
635

    
636
### polygon()
637

    
638
Specifies a `$polygon` condition
639

    
640
```js
641
mquery().where('loc').within().polygon([10,20], [13, 25], [7,15])
642
mquery().polygon('loc', [10,20], [13, 25], [7,15])
643
```
644

    
645
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/polygon/)
646

    
647
### regex()
648

    
649
Specifies a `$regex` query condition.
650

    
651
```js
652
mquery().where('name').regex(/^sixstepsrecords/)
653
```
654

    
655
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/regex/)
656

    
657
### select()
658

    
659
Specifies which document fields to include or exclude
660

    
661
```js
662
// 1 means include, 0 means exclude
663
mquery().select({ name: 1, address: 1, _id: 0 })
664

    
665
// or
666

    
667
mquery().select('name address -_id')
668
```
669

    
670
##### String syntax
671

    
672
When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included.
673

    
674
```js
675
// include a and b, exclude c
676
query.select('a b -c');
677

    
678
// or you may use object notation, useful when
679
// you have keys already prefixed with a "-"
680
query.select({a: 1, b: 1, c: 0});
681
```
682

    
683
_Cannot be used with `distinct()`._
684

    
685
### selected()
686

    
687
Determines if the query has selected any fields.
688

    
689
```js
690
var query = mquery();
691
query.selected() // false
692
query.select('-name');
693
query.selected() // true
694
```
695

    
696
### selectedInclusively()
697

    
698
Determines if the query has selected any fields inclusively.
699

    
700
```js
701
var query = mquery().select('name');
702
query.selectedInclusively() // true
703

    
704
var query = mquery();
705
query.selected() // false
706
query.select('-name');
707
query.selectedInclusively() // false
708
query.selectedExclusively() // true
709
```
710

    
711
### selectedExclusively()
712

    
713
Determines if the query has selected any fields exclusively.
714

    
715
```js
716
var query = mquery().select('-name');
717
query.selectedExclusively() // true
718

    
719
var query = mquery();
720
query.selected() // false
721
query.select('name');
722
query.selectedExclusively() // false
723
query.selectedInclusively() // true
724
```
725

    
726
### size()
727

    
728
Specifies a `$size` query condition.
729

    
730
```js
731
mquery().where('someArray').size(6)
732
```
733

    
734
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/size/)
735

    
736
### slice()
737

    
738
Specifies a `$slice` projection for a `path`
739

    
740
```js
741
mquery().where('comments').slice(5)
742
mquery().where('comments').slice(-5)
743
mquery().where('comments').slice([-10, 5])
744
```
745

    
746
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/projection/slice/)
747

    
748
### within()
749

    
750
Sets a `$geoWithin` or `$within` argument for geo-spatial queries.
751

    
752
```js
753
mquery().within().box()
754
mquery().within().circle()
755
mquery().within().geometry()
756

    
757
mquery().where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
758
mquery().where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
759
mquery().where('loc').within({ polygon: [[],[],[],[]] });
760

    
761
mquery().where('loc').within([], [], []) // polygon
762
mquery().where('loc').within([], []) // box
763
mquery().where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
764
```
765

    
766
As of mquery 2.0, `$geoWithin` is used by default. This impacts you if running MongoDB < 2.4. To alter this behavior, see [mquery.use$geoWithin](#mqueryusegeowithin).
767

    
768
**Must** be used after `where()`.
769

    
770
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoWithin/)
771

    
772
### where()
773

    
774
Specifies a `path` for use with chaining
775

    
776
```js
777
// instead of writing:
778
mquery().find({age: {$gte: 21, $lte: 65}});
779

    
780
// we can instead write:
781
mquery().where('age').gte(21).lte(65);
782

    
783
// passing query conditions is permitted too
784
mquery().find().where({ name: 'vonderful' })
785

    
786
// chaining
787
mquery()
788
.where('age').gte(21).lte(65)
789
.where({ 'name': /^vonderful/i })
790
.where('friends').slice(10)
791
.exec(callback)
792
```
793

    
794
### $where()
795

    
796
Specifies a `$where` condition.
797

    
798
Use `$where` when you need to select documents using a JavaScript expression.
799

    
800
```js
801
query.$where('this.comments.length > 10 || this.name.length > 5').exec(callback)
802

    
803
query.$where(function () {
804
  return this.comments.length > 10 || this.name.length > 5;
805
})
806
```
807

    
808
Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.
809

    
810
-----------
811

    
812
### batchSize()
813

    
814
Specifies the batchSize option.
815

    
816
```js
817
query.batchSize(100)
818
```
819

    
820
_Cannot be used with `distinct()`._
821

    
822
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/)
823

    
824
### comment()
825

    
826
Specifies the comment option.
827

    
828
```js
829
query.comment('login query');
830
```
831

    
832
_Cannot be used with `distinct()`._
833

    
834
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/)
835

    
836
### hint()
837

    
838
Sets query hints.
839

    
840
```js
841
mquery().hint({ indexA: 1, indexB: -1 })
842
```
843

    
844
_Cannot be used with `distinct()`._
845

    
846
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/hint/)
847

    
848
### limit()
849

    
850
Specifies the limit option.
851

    
852
```js
853
query.limit(20)
854
```
855

    
856
_Cannot be used with `distinct()`._
857

    
858
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.limit/)
859

    
860
### maxScan()
861

    
862
Specifies the maxScan option.
863

    
864
```js
865
query.maxScan(100)
866
```
867

    
868
_Cannot be used with `distinct()`._
869

    
870
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/maxScan/)
871

    
872
### maxTime()
873

    
874
Specifies the maxTimeMS option.
875

    
876
```js
877
query.maxTime(100)
878
```
879

    
880
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.maxTimeMS/)
881

    
882

    
883
### skip()
884

    
885
Specifies the skip option.
886

    
887
```js
888
query.skip(100).limit(20)
889
```
890

    
891
_Cannot be used with `distinct()`._
892

    
893
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.skip/)
894

    
895
### sort()
896

    
897
Sets the query sort order.
898

    
899
If an object is passed, key values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
900

    
901
If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
902

    
903
```js
904
// these are equivalent
905
query.sort({ field: 'asc', test: -1 });
906
query.sort('field -test');
907
```
908

    
909
_Cannot be used with `distinct()`._
910

    
911
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.sort/)
912

    
913
### read()
914

    
915
Sets the readPreference option for the query.
916

    
917
```js
918
mquery().read('primary')
919
mquery().read('p')  // same as primary
920

    
921
mquery().read('primaryPreferred')
922
mquery().read('pp') // same as primaryPreferred
923

    
924
mquery().read('secondary')
925
mquery().read('s')  // same as secondary
926

    
927
mquery().read('secondaryPreferred')
928
mquery().read('sp') // same as secondaryPreferred
929

    
930
mquery().read('nearest')
931
mquery().read('n')  // same as nearest
932
```
933

    
934
##### Preferences:
935

    
936
- `primary` - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
937
- `secondary` - Read from secondary if available, otherwise error.
938
- `primaryPreferred` - Read from primary if available, otherwise a secondary.
939
- `secondaryPreferred` - Read from a secondary if available, otherwise read from the primary.
940
- `nearest` - All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.
941

    
942
Aliases
943

    
944
- `p`   primary
945
- `pp`  primaryPreferred
946
- `s`   secondary
947
- `sp`  secondaryPreferred
948
- `n`   nearest
949

    
950
##### Preference Tags:
951

    
952
To keep the separation of concerns between `mquery` and your driver
953
clean, `mquery#read()` no longer handles specifying a second `tags` argument as of version 0.5.
954
If you need to specify tags, pass any non-string argument as the first argument.
955
`mquery` will pass this argument untouched to your collections methods later.
956
For example:
957

    
958
```js
959
// example of specifying tags using the Node.js driver
960
var ReadPref = require('mongodb').ReadPreference;
961
var preference = new ReadPref('secondary', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }]);
962
mquery(..).read(preference).exec();
963
```
964

    
965
Read more about how to use read preferences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).
966

    
967
### slaveOk()
968

    
969
Sets the slaveOk option. `true` allows reading from secondaries.
970

    
971
**deprecated** use [read()](#read) preferences instead if on mongodb >= 2.2
972

    
973
```js
974
query.slaveOk() // true
975
query.slaveOk(true)
976
query.slaveOk(false)
977
```
978

    
979
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/rs.slaveOk/)
980

    
981
### snapshot()
982

    
983
Specifies this query as a snapshot query.
984

    
985
```js
986
mquery().snapshot() // true
987
mquery().snapshot(true)
988
mquery().snapshot(false)
989
```
990

    
991
_Cannot be used with `distinct()`._
992

    
993
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/snapshot/)
994

    
995
### tailable()
996

    
997
Sets tailable option.
998

    
999
```js
1000
mquery().tailable() <== true
1001
mquery().tailable(true)
1002
mquery().tailable(false)
1003
```
1004

    
1005
_Cannot be used with `distinct()`._
1006

    
1007
[MongoDB Documentation](http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/)
1008

    
1009
## Helpers
1010

    
1011
### collection()
1012

    
1013
Sets the querys collection.
1014

    
1015
```js
1016
mquery().collection(aCollection)
1017
```
1018

    
1019
### then()
1020

    
1021
Executes the query and returns a promise which will be resolved with the query results or rejected if the query responds with an error.
1022

    
1023
```js
1024
mquery().find(..).then(success, error);
1025
```
1026

    
1027
This is very useful when combined with [co](https://github.com/visionmedia/co) or [koa](https://github.com/koajs/koa), which automatically resolve promise-like objects for you.
1028

    
1029
```js
1030
co(function*(){
1031
  var doc = yield mquery().findOne({ _id: 499 });
1032
  console.log(doc); // { _id: 499, name: 'amazing', .. }
1033
})();
1034
```
1035

    
1036
_NOTE_:
1037
The returned promise is a [bluebird](https://github.com/petkaantonov/bluebird/) promise but this is customizable. If you want to
1038
use your favorite promise library, simply set `mquery.Promise = YourPromiseConstructor`.
1039
Your `Promise` must be [promises A+](http://promisesaplus.com/) compliant.
1040

    
1041
### thunk()
1042

    
1043
Returns a thunk which when called runs the query's `exec` method passing the results to the callback.
1044

    
1045
```js
1046
var thunk = mquery(collection).find({..}).thunk();
1047

    
1048
thunk(function(err, results) {
1049

    
1050
})
1051
```
1052

    
1053
### merge(object)
1054

    
1055
Merges other mquery or match condition objects into this one. When an mquery instance is passed, its match conditions, field selection and options are merged.
1056

    
1057
```js
1058
var drum = mquery({ type: 'drum' }).collection(instruments);
1059
var redDrum = mquery({ color: 'red' }).merge(drum);
1060
redDrum.count(function (err, n) {
1061
  console.log('there are %d red drums', n);
1062
})
1063
```
1064

    
1065
Internally uses `mquery.canMerge` to determine validity.
1066

    
1067
### setOptions(options)
1068

    
1069
Sets query options.
1070

    
1071
```js
1072
mquery().setOptions({ collection: coll, limit: 20 })
1073
```
1074

    
1075
##### options
1076

    
1077
- [tailable](#tailable) *
1078
- [sort](#sort) *
1079
- [limit](#limit) *
1080
- [skip](#skip) *
1081
- [maxScan](#maxscan) *
1082
- [maxTime](#maxtime) *
1083
- [batchSize](#batchSize) *
1084
- [comment](#comment) *
1085
- [snapshot](#snapshot) *
1086
- [hint](#hint) *
1087
- [slaveOk](#slaveOk) *
1088
- [safe](http://docs.mongodb.org/manual/reference/write-concern/): Boolean - passed through to the collection. Setting to `true` is equivalent to `{ w: 1 }`
1089
- [collection](#collection): the collection to query against
1090

    
1091
_* denotes a query helper method is also available_
1092

    
1093
### setTraceFunction(func)
1094

    
1095
Set a function to trace this query. Useful for profiling or logging.
1096

    
1097
```js
1098
function traceFunction (method, queryInfo, query) {
1099
  console.log('starting ' + method + ' query');
1100

    
1101
  return function (err, result, millis) {
1102
    console.log('finished ' + method + ' query in ' + millis + 'ms');
1103
  };
1104
}
1105

    
1106
mquery().setTraceFunction(traceFunction).findOne({name: 'Joe'}, cb);
1107
```
1108

    
1109
The trace function is passed (method, queryInfo, query)
1110

    
1111
- method is the name of the method being called (e.g. findOne)
1112
- queryInfo contains information about the query:
1113
 - conditions: query conditions/criteria
1114
 - options: options such as sort, fields, etc
1115
 - doc: document being updated
1116
- query is the query object
1117

    
1118
The trace function should return a callback function which accepts:
1119
- err: error, if any
1120
- result: result, if any
1121
- millis: time spent waiting for query result
1122

    
1123
NOTE: stream requests are not traced.
1124

    
1125
### mquery.setGlobalTraceFunction(func)
1126

    
1127
Similar to `setTraceFunction()` but automatically applied to all queries.
1128

    
1129
```js
1130
mquery.setTraceFunction(traceFunction);
1131
```
1132

    
1133
### mquery.canMerge(conditions)
1134

    
1135
Determines if `conditions` can be merged using `mquery().merge()`.
1136

    
1137
```js
1138
var query = mquery({ type: 'drum' });
1139
var okToMerge = mquery.canMerge(anObject)
1140
if (okToMerge) {
1141
  query.merge(anObject);
1142
}
1143
```
1144

    
1145
## mquery.use$geoWithin
1146

    
1147
MongoDB 2.4 introduced the `$geoWithin` operator which replaces and is 100% backward compatible with `$within`. As of mquery 0.2, we default to using `$geoWithin` for all `within()` calls.
1148

    
1149
If you are running MongoDB < 2.4 this will be problematic. To force `mquery` to be backward compatible and always use `$within`, set the `mquery.use$geoWithin` flag to `false`.
1150

    
1151
```js
1152
mquery.use$geoWithin = false;
1153
```
1154

    
1155
## Custom Base Queries
1156

    
1157
Often times we want custom base queries that encapsulate predefined criteria. With `mquery` this is easy. First create the query you want to reuse and call its `toConstructor()` method which returns a new subclass of `mquery` that retains all options and criteria of the original.
1158

    
1159
```js
1160
var greatMovies = mquery(movieCollection).where('rating').gte(4.5).toConstructor();
1161

    
1162
// use it!
1163
greatMovies().count(function (err, n) {
1164
  console.log('There are %d great movies', n);
1165
});
1166

    
1167
greatMovies().where({ name: /^Life/ }).select('name').find(function (err, docs) {
1168
  console.log(docs);
1169
});
1170
```
1171

    
1172
## Validation
1173

    
1174
Method and options combinations are checked for validity at runtime to prevent creation of invalid query constructs. For example, a `distinct` query does not support specifying options like `hint` or field selection. In this case an error will be thrown so you can catch these mistakes in development.
1175

    
1176
## Debug support
1177

    
1178
Debug mode is provided through the use of the [debug](https://github.com/visionmedia/debug) module. To enable:
1179

    
1180
    DEBUG=mquery node yourprogram.js
1181

    
1182
Read the debug module documentation for more details.
1183

    
1184
## General compatibility
1185

    
1186
#### ObjectIds
1187

    
1188
`mquery` clones query arguments before passing them to a `collection` method for execution.
1189
This prevents accidental side-affects to the objects you pass.
1190
To clone `ObjectIds` we need to make some assumptions.
1191

    
1192
First, to check if an object is an `ObjectId`, we check its constructors name. If it matches either
1193
`ObjectId` or `ObjectID` we clone it.
1194

    
1195
To clone `ObjectIds`, we call its optional `clone` method. If a `clone` method does not exist, we fall
1196
back to calling `new obj.constructor(obj.id)`. We assume, for compatibility with the
1197
Node.js driver, that the `ObjectId` instance has a public `id` property and that
1198
when creating an `ObjectId` instance we can pass that `id` as an argument.
1199

    
1200
#### Read Preferences
1201

    
1202
`mquery` supports specifying [Read Preferences]() to control from which MongoDB node your query will read.
1203
The Read Preferences spec also support specifying tags. To pass tags, some
1204
drivers (Node.js driver) require passing a special constructor that handles both the read preference and its tags.
1205
If you need to specify tags, pass an instance of your drivers ReadPreference constructor or roll your own. `mquery` will store whatever you provide and pass later to your collection during execution.
1206

    
1207
## Future goals
1208

    
1209
  - mongo shell compatibility
1210
  - browser compatibility
1211

    
1212
## Installation
1213

    
1214
    $ npm install mquery
1215

    
1216
## License
1217

    
1218
[MIT](https://github.com/aheckmann/mquery/blob/master/LICENSE)
1219