Skip to content

Commit bffdc46

Browse files
authored
Merge pull request #4 from hiveteams/master
Set reactive callbacks based on whether or not cursor is ordered
2 parents cfdfc22 + 6c5e53b commit bffdc46

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,60 @@ Installation
2323
meteor add peerlibrary:reactive-mongo
2424
```
2525

26+
Invalidating computations on Ordered vs. Unordered cursors
27+
------------
28+
In Meteor, there's a concept of `ordered` cursors. If a cursor is `ordered`, then when the order of the documents in the result set changes, the computation will be invalidated and the `autorun` will re-run.
29+
30+
By default, this package will use an ordered cursor if a `sort` is present in the query. If no `sort` is specified, it will use an unordered cursor.
31+
32+
To override the defualt functionality, you can explicitly force or un-force `ordered` by passing an `ordered` option to your `find`:
33+
34+
```
35+
// Server code
36+
37+
// Will use ordered since a sort is present
38+
Tracker.autorun(() => {
39+
Posts.find({ topic: 'news' }, { sort: { name: 1 } }).fetch();
40+
});
41+
42+
// Will use unordered since no sort is present
43+
Tracker.autorun(() => {
44+
Posts.find({ topic: 'news' }).fetch();
45+
});
46+
47+
// Will not use ordered since the option is forced to "false"
48+
Tracker.autorun(() => {
49+
Posts.find({ topic: 'news' }, { sort: { name: 1 }, ordered: false }).fetch();
50+
});
51+
52+
// Will use ordered since the option is forced to "true"
53+
Tracker.autorun(() => {
54+
Posts.find({ topic: 'news' }, ordered: true }).fetch();
55+
});
56+
```
57+
58+
Polling vs. Oplog inside autoruns
59+
------------
60+
A common use case for server autoruns is using a `findOne` to do a reactive join. Meteor's server-side `findOne` is a `find(selector, { limit: 1 }).fetch()[0]` [under the hood](https://github.com/meteor/meteor/blob/devel/packages/mongo/mongo_driver.js#L784). [Because Meteor Oplog does not support](https://galaxy-guide.meteor.com/apm-optimize-your-app-for-oplog.html#Limit-Without-Sort) `limit` without `sort`, calling `Collection.findOne(someId)` in a server autorun will default to using polling.
61+
62+
63+
If you'd like queries inside a server autorun to use Oplog, you'll need to specify a sort for your `findOne` **and** pass `ordered: false` to use unordered cursor:
64+
65+
```
66+
// Server code
67+
68+
// Will use oplog since it has sort, limit, and is unordered
69+
Tracker.autorun(() => {
70+
Collection.findOne(someId, { sort: { _id: 1 }, ordered: false });
71+
});
72+
73+
// Will use polling because a limit (from findOne) but no sort is specified
74+
Tracker.autorun(() => {
75+
Collection.findOne(someId);
76+
});
77+
```
78+
79+
2680
Acknowledgments
2781
---------------
2882

server.coffee

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,29 @@ MeteorCursor::observeChanges = (options) ->
4040
handle.stop()
4141
handle
4242

43+
callbacksOrdered =
44+
addedBefore: true
45+
removed: true
46+
changed: true
47+
movedBefore: true
48+
49+
callbacksUnordered =
50+
added: true
51+
changed: true
52+
removed: true
53+
4354
for method in ['forEach', 'map', 'fetch']
4455
do (method) ->
4556
originalMethod = MeteorCursor::[method]
4657
MeteorCursor::[method] = (args...) ->
4758
if @_isReactive()
48-
@_depend
49-
addedBefore: true
50-
removed: true
51-
changed: true
52-
movedBefore: true
59+
{sort, ordered} = @_cursorDescription.options
60+
useOrderedOption = ordered != undefined
61+
if useOrderedOption
62+
callbacks = if ordered then callbacksOrdered else callbacksUnordered
63+
else
64+
callbacks = if !!sort then callbacksOrdered else callbacksUnordered
65+
@_depend callbacks
5366

5467
originalMethod.apply @, args
5568

0 commit comments

Comments
 (0)