diff --git a/README.md b/README.md index ae92a95..9354048 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,40 @@ Template.searchResult.helpers({ }); ``` +### Use reactive data in search results + +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 + +```js +var options = { + keepHistory: 1000 * 60 * 5, + localSearch: true, + collection: Documents, // Collection to reflect on the client + subscriptionName: 'documents.byIds' // Use subscription by this name +}; + +// Some fields +const fields = [ 'name', 'description' ]; + +const DocumentSearch = new SearchSource('docs', fields, options); +``` + +and on the server, publish the documents by ids + +```js +Meteor.publish('documents.byIds', function (ids) { + check(ids, [ String ]); + + return Documents.find({ + _id: { + $in: ids + } + }); +}); +``` + +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. + ### Searching Finally we can invoke search queries by invoking following API. diff --git a/lib/client.js b/lib/client.js index 3963ab8..98077ce 100644 --- a/lib/client.js +++ b/lib/client.js @@ -19,6 +19,7 @@ SearchSource.prototype._loadData = function(query, options) { var self = this; var version = 0; var historyKey = query + EJSON.stringify(options); + if(this._canUseHistory(historyKey)) { this._updateStore(this.history[historyKey].data); this.metaData.set(this.history[historyKey].metadata); @@ -149,6 +150,36 @@ SearchSource.prototype.getData = function(options, getCursor) { transform: transform }); + var collection = this.options.collection; + + if(collection) { + var ids = _.pluck(cursor.fetch(), '_id'); + + if (!this.options.subscriptionName) { + throw Error('subscritionName is missing'); + } + + var sub = Meteor.subscribe(this.options.subscriptionName, ids); + + if (!sub.ready()) + return []; + + var docs = collection.find({ + _id: { + $in: ids + } + }, { + transform: transform + }).fetch(); + + var sortIds = _.invert(_.object(_.pairs(ids))); + var sorted = _.sortBy(docs, function(x) { + return sortIds[x._id]; + }); + + return sorted; + } + if(getCursor) { return cursor; } @@ -234,4 +265,4 @@ SearchSource.prototype._getRegExpFilterRegExp = _.once(function() { return "\\" + c; }).join("|"); return new RegExp("(" + regExpCharsReplace + ")", "g"); -}); \ No newline at end of file +});