Skip to content

Commit 2cc8065

Browse files
committed
Reactive search results. Performance is not considered while implementing this.
1 parent 351b2c3 commit 2cc8065

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

README.md

+34
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,40 @@ Template.searchResult.helpers({
100100
});
101101
```
102102

103+
### Use reactive data in search results
104+
105+
By default, the contents returned by `getData()` is not reactive in the sense of it reflecting the current state of the mongo database. To use reactive content, do the following when creating a SearchSource object on the client
106+
107+
```js
108+
var options = {
109+
keepHistory: 1000 * 60 * 5,
110+
localSearch: true,
111+
collection: Documents, // Collection to reflect on the client
112+
subscriptionName: 'documents.byIds' // Use subscription by this name
113+
};
114+
115+
// Some fields
116+
const fields = [ 'name', 'description' ];
117+
118+
const DocumentSearch = new SearchSource('docs', fields, options);
119+
```
120+
121+
and on the server, publish the documents by ids
122+
123+
```js
124+
Meteor.publish('documents.byIds', function (ids) {
125+
check(ids, [ String ]);
126+
127+
return Documents.find({
128+
_id: {
129+
$in: ids
130+
}
131+
});
132+
});
133+
```
134+
135+
and the rest is as usual. One thing to notice is that `getData()` cannot return a cursor if reactive items are used. This is because we sort documents on a score field that is not attached to the documents itself, so mongo cannot take care of the ordering.
136+
103137
### Searching
104138

105139
Finally we can invoke search queries by invoking following API.

lib/client.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SearchSource.prototype._loadData = function(query, options) {
1919
var self = this;
2020
var version = 0;
2121
var historyKey = query + EJSON.stringify(options);
22+
2223
if(this._canUseHistory(historyKey)) {
2324
this._updateStore(this.history[historyKey].data);
2425
this.metaData.set(this.history[historyKey].metadata);
@@ -149,6 +150,36 @@ SearchSource.prototype.getData = function(options, getCursor) {
149150
transform: transform
150151
});
151152

153+
var collection = this.options.collection;
154+
155+
if(collection) {
156+
var ids = _.pluck(cursor.fetch(), '_id');
157+
158+
if (!this.options.subscriptionName) {
159+
throw Error('subscritionName is missing');
160+
}
161+
162+
var sub = Meteor.subscribe(this.options.subscriptionName, ids);
163+
164+
if (!sub.ready())
165+
return [];
166+
167+
var docs = collection.find({
168+
_id: {
169+
$in: ids
170+
}
171+
}, {
172+
transform: transform
173+
}).fetch();
174+
175+
var sortIds = _.invert(_.object(_.pairs(ids)));
176+
var sorted = _.sortBy(docs, function(x) {
177+
return sortIds[x._id];
178+
});
179+
180+
return sorted;
181+
}
182+
152183
if(getCursor) {
153184
return cursor;
154185
}
@@ -234,4 +265,4 @@ SearchSource.prototype._getRegExpFilterRegExp = _.once(function() {
234265
return "\\" + c;
235266
}).join("|");
236267
return new RegExp("(" + regExpCharsReplace + ")", "g");
237-
});
268+
});

0 commit comments

Comments
 (0)