meteorhacks / search-source Goto Github PK
View Code? Open in Web Editor NEWReactive Data Source for Search
License: MIT License
Reactive Data Source for Search
License: MIT License
hi there,
great solution, congrats!
I would suggest to let a func call trigger the re-scan of the collection following an insert/update/delete
what do you think?
cheers,
tinto
Greetings! I'm working through your example (thank you) however running into problems getting the transform to fire.
The docTransform hits every time. But never the transform.
Any ideas?
`Template.SearchResults.helpers({
offender: function() {
return OffenderSearch.getData({
transform: function (matchText, regExp) {
console.log('hit transform');
return matchText.replace(regExp, "<b>$&</b>");
},
docTransform: function(doc) {
console.log('hit docTransform');
return doc;
}
});
}`
What would be the best strategy to create a dropbown autocomplete for form input fields with search-source?
Similar to Select2, but just for a regular input.
This takes data from Google, but I am just talking about the styling of searching my own data and then putting results in a dropdown to insert in a form that will be submitted:
https://github.com/comerc/meteor-autoform-placecomplete/
This package is close, but is missing your search-source features of bolding the text that matches:
https://github.com/miguelalarcos/afwrap-xautocomplete/
It seems I would be able to put the search results right under the form field input, have it floating with css, and then make arrow key functionality/ clicking functionality, then have it disappear.
But I don't want to reinvent the wheel, is there a better way?
Example, I have an address form with inputs:
Customer
Company
Street1
Street2
City
State
Zip
And I want to search my Addresses collection on each of those fields, with a similar interface to select2 where the search results are right under the form field temporarily, I select one with arrow keys or the mouse, and then it inserts that value in the form.
Any ideas?
Thank you.
Getting strange random error, not sure exactly how to solve, search still works but stay loading forever and seems to cause cpu/memory leaks.
Exception in delivering result of invoking 'search.source': TypeError: Cannot read property 'str' of undefined
at http://localhost:3000/packages/meteorhacks_search-source.js?b3122033999151d35259310e0ffa257e17669508:125:25
at Array.forEach (native)
at Function..each._.forEach (http://localhost:3000/packages/underscore.js?0a80a8623e1b40b5df5a05582f288ddd586eaa18:156:11)
at SearchSource._updateStore (http://localhost:3000/packages/meteorhacks_search-source.js?b3122033999151d35259310e0ffa257e17669508:123:5)
at handleData (http://localhost:3000/packages/meteorhacks_search-source.js?b3122033999151d35259310e0ffa257e17669508:89:14)
at Meteor.bindEnvironment as _callback
at _.extend._maybeInvokeCallback (http://localhost:3000/packages/ddp.js?d1840d3ba04c65ffade261f362e26699b7509706:3860:12)
at _.extend.receiveResult (http://localhost:3000/packages/ddp.js?d1840d3ba04c65ffade261f362e26699b7509706:3880:10)
at _.extend._livedata_result (http://localhost:3000/packages/ddp.js?d1840d3ba04c65ffade261f362e26699b7509706:4970:9)
at onMessage (http://localhost:3000/packages/ddp.js?d1840d3ba04c65ffade261f362e26699b7509706:3725:12)
This is very frustrating, because this is the first addon I try and it simply doesn´t work.
Console keeps telling me "Exception in delivering result of invoking 'search.source': Error: Internal server error [500]" each time I try to give it a try. The full stack is this:
Exception in delivering result of invoking 'search.source': Error: Internal server error [500]
at .extend.livedata_result (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:4625:23)
at onMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3365:12)
at http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2734:11
at Array.forEach (native)
at Function..each..forEach (http://localhost:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:149:11)
at self.socket.onmessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2733:11)
at REventTarget.dispatchEvent (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:173:22)
at SockJS._dispatchMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1158:10)
at SockJS._didMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1216:18)
at WebSocket.that.ws.onmessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1363:17)
I recently tried to update my project with a search module built on search-source to meteor 1.2.
The search module is now out of service.
Do you have a workaround?
Hi @arunoda,
I tried to look in the docs for what isoScore
does but could not find it. Is it something that is used internally? Is it used to indicate the search weight-age and provide more importance to some fields?
PS. Thanks for the awesome package (and the million other things you did for the Meteor community :)
I have the data source on the client side. How can I use that?
If I wanted to let the user filter or change sort, is that doable with search-source? Would be good to have some mention of this on the wiki as I prefer the implementation of this over easysearch but would like to be able to filter/sort
I am trying to use this package to search in nested fields of a document but it seems to cause a problem with the transform function on the client. (maybe by accessing the document fields like
doc[field]
is causing the issue ?)
I am not really a js guy so I might be completely out.
Wich notation should we use to define the search in nested fields ?
Not sure where to even start with this one. Any ideas?
SearchSource.defineSource("bookings", function(searchText, options) {
var options = (typeof options == "object") ? options : { sort: { isoScore: -1 }, limit: 20 };
if(searchText) {
var regExp = new RegExp("(" + searchText.trim().split(" ").join("|") + ")", "ig");
console.info(searchText, regExp);
var selector = { $or: [
{ customer: regExp },
{ notes: regExp }
]};
return Bookings.find(selector, options).fetch();
}
else {
return Bookings.find({}, options).fetch();
}
});
Apparently search is only possible with a single textual keyword. I wonder if I am right and if there is any reason for this design choice. Do you think a generic search using a kind of Mongodb query selector would make sense?
Thanks
First of all: I really like this package, it helps a lot to implement search functionality.
Today, I tried to set-up a search that uses an array of strings instead of a plain string as an input parameter. This did not work. Instead, I got the following error message:
I20151106-13:55:32.616(1)? Exception while invoking method 'search.source' Error: Match error: Failed Match.OneOf or Match.Optional validation
I20151106-13:55:32.616(1)? at checkSubtree (packages/check/match.js:244:1)
I20151106-13:55:32.616(1)? at check (packages/check/match.js:32:1)
I20151106-13:55:32.617(1)? at [object Object].Meteor.methods.search.source (packages/meteorhacks:search-source/lib/server.js:12:1)
I20151106-13:55:32.617(1)? at [object Object].methodMap.(anonymous function) (packages/meteorhacks:kadira/lib/hijack/wrap_session.js:164:1)
I20151106-13:55:32.617(1)? at packages/check/match.js:109:1
I20151106-13:55:32.617(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20151106-13:55:32.617(1)? at Object.Match._failIfArgumentsAreNotAllChecked (packages/check/match.js:108:1)
I20151106-13:55:32.617(1)? at maybeAuditArgumentChecks (packages/ddp/livedata_server.js:1614:1)
I20151106-13:55:32.617(1)? at packages/ddp/livedata_server.js:648:1
I20151106-13:55:32.617(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20151106-13:55:32.617(1)? Sanitized and reported to the client as: Match failed [400]
I20151106-13:55:32.617(1)?
Is there any particular reason why the input parameter is limited to a string? I will now concat the array using a delimiter character as a work-around, but it would be nicer if I could send arrays or plain objects directly.
Problem is with the following code in client.js (and especially the _buildRegExp
function):
// only do client side searching if we are on the loading state
// once loaded, we need to send all of them
if(this.getStatus().loading) {
self.searchFields.forEach(function(field) {
var singleQuery = {};
singleQuery[field] = regExp;
selector['$or'].push(singleQuery);
});
} else {
selector = {};
}
If my query is "oeuf" and cached results contain a field value "œuf" (note the œ), when the search will be in "loading" state, "œuf" will disappear, until the search will switch in "loaded" state.
This would be a great feature:
If my ES type, for example items
, is a mirror of a Mongo collection Items
, it would be great if SearchSource
could add the search results to the local client Items._collection
so that I can do Items.find x
and get results that were either published OR found through an ES search.
I want something like this:
SearchSource.defineSource 'items', (text, options) ->
selector = {}
if text
regExp = buildRegExp text
selector =
name: regExp
result =
items: Items.find(selector, options).fetch()
count: Items.find(selector).count()
return result
If one of the searchable fields is an array this code doesn't work:
return PackagesSearch.getData({
transform: function(matchText, regExp) {
return matchText.replace(regExp, "<b>$&</b>")
},
sort: {date: -1}
});
I have to implement global search in my app. It should show search results from Clients, Projects, Orders and Suppliers collections into one list.
Is search-source good choice to do that? If yes, any examples? If not, then also ok, I will just look for some other solutions... ;)
Thanks for any answers.
Hello! This is fantastic.
Is it possible to search multiple collections in one search?
Thank you!
Hi,
Im not able to get the search reults working.. I can get the loading, but nothing returned from the search..
Im getting this error, I think it maybe a conflict with the astronomy package? anyone run into this?
Exception while parsing DDP TypeError: Class is not a function
at http://localhost:3000/packages/jagi_astronomy.js?7b384fdfe81e7bfd1de7bea7ca6b668df971710b:1590:13
at http://localhost:3000/packages/ejson.js?6b2a6aad82b5a8eb6d5f26975783b243b6df124a:214:16
at Object.Meteor.noYieldsAllowed (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:650:10)
at Object.builtinConverters.fromJSONValue (http://localhost:3000/packages/ejson.js?6b2a6aad82b5a8eb6d5f26975783b243b6df124a:213:21)
at fromJSONValueHelper (http://localhost:3000/packages/ejson.js?6b2a6aad82b5a8eb6d5f26975783b243b6df124a:340:28)
at http://localhost:3000/packages/ejson.js?6b2a6aad82b5a8eb6d5f26975783b243b6df124a:313:21
at Array.forEach (native)
at Function..each._.forEach (http://localhost:3000/packages/underscore.js?fa590de5090ceb4a42555b48562fd8f8e7035758:157:11)
at Object.EJSON._adjustTypesFromJSONValue (http://localhost:3000/packages/ejson.js?6b2a6aad82b5a8eb6d5f26975783b243b6df124a:311:5)
at http://localhost:3000/packages/ddp-common.js?5bfbe93c6ad5580f8d13f28d81b2c0db0dae13c4:210:26
I would like to search in an input search box for the _id so it can be displayed in the results. Any ideas how to achieve this? I am new to meteor, btw.
var selector = {name: regExp, _id: regExp};
Hello. I'm trying to implement this package but have an error:
Exception while invoking method 'search.source' Error: Match error: Failed Match.OneOf or Match.Optional validation
at check (packages/check/match.js:33:1)
at [object Object]._.extend._getFindOptions (packages/mongo/collection.js:248:1)
at [object Object]._.extend.find (packages/mongo/collection.js:284:1)
at [object Object].<anonymous> (server/search-source.js:7:1)
at [object Object].getSourceData (packages/meteorhacks_search-source/lib/server.js:65:1)
at [object Object].Meteor.methods.search.source (packages/meteorhacks_search-source/lib/server.js:18:1)
at maybeAuditArgumentChecks (livedata_server.js:1698:12)
at livedata_server.js:708:19
at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
at livedata_server.js:706:40
Sanitized and reported to the client as: Match failed [400]
Here is my code.
Client
var options = {
keepHistory: 1000 * 60 * 5,
localSearch: true
};
var fields = ['exerciseName', 'exerciseDesc'];
ExercisesSearch = new SearchSource('exercises', fields, options);
Server
SearchSource.defineSource('exercises', function(searchText, options) {
//var options = {sort: {isoScore: -1}, limit: 20};
if(searchText) {
var regExp = buildRegExp(searchText);
var selector = {exerciseName: regExp, exerciseDesc: regExp};
return Exercises.find(selector, options).fetch();
} else {
return Exercises.find({}, options).fetch();
}
});
function buildRegExp(searchText) {
var words = searchText.trim().split(/[ \-\:]+/);
var exps = _.map(words, function(word) {
return "(?=.*" + word + ")";
});
var fullExp = exps.join('') + ".+";
return new RegExp(fullExp, "i");
}
I have a collection
marks {
testers: {
{
"class": "math",
"mark": 81
},
{
"class": "english",
"mark": 90
}
}
}
So, my server method is
SearchSource.defineSource('packages', function(searchText, options) {
console.dir(searchText);
if(searchText) {
var regExp = buildRegExp(searchText);
var options = {limit: 20};
var selector = {"testers.class": regExp}
return marks.find(selector, options).fetch();
}
} else {
return marks.find({}, options).fetch();
}
});
This returns every single 'class' object if one of them matches the search query. If I search "english", I want it to just return the word 'english'. How can I do this?
Hi,
I tried to use the API getMetadata to get the number of results for a certain search but I can get it working. Could you provide a working example?
I defined an helper:
Template.toursSearchResults.helpers({
meta: function() {
console.log("METADATA: " + TourSearch.getMetadata());
return TourSearch.getMetadata();
}
});
I defined a server searchSource:
SearchSource.defineSource('tours', function(searchText, options) {
var options = {sort: {submitted: -1}, limit: 20};
if(searchText) {
var regExp = buildRegExp(searchText);
var selector = {$or: [
{title: regExp},
{summary: regExp}
]};
return Tours.find(selector, options).fetch();
// var data = getSearchResult(searchText);
// var metadata = getMetadata();
// return {
// data: data,
// metadata: metadata
// }
} else {
return Tours.find({}, options).fetch();
}
});
function buildRegExp(searchText) {
// this is a dumb implementation
var parts = searchText.trim().split(/[ \-\:]+/);
return new RegExp("(" + parts.join('|') + ")", "ig");
}
And i am calling the search in the helper at the keyup as in you example:
Template.toursSearchBox.events({
"keyup #search-box": _.throttle(function(e) {
var text = $(e.target).val().trim();
TourSearch.search(text);
}, 200)
});
But i cannot get the metadata. In the browser console i get an empty metadata object. If i uncomment the getMetadata() call in the searchSource server side definition I get a getMetadata is not defined.
Could you help me understand where is the error?
Thank you for your great job!
For example, "Search Source" would give matches for "Search", "Source", and "Search Source". Is there a way to restrict the search so that it only gives matches for the whole phrase, "Search Source"?
x
I'm using getData() as described in the docs, as part of a helper. I've noticed that this helper is run three times (instead of one time), if a new search is executed. This causes problems, because I would like to animate the display of the results. If you don't animate it, you won't notice the 3 renderings, but if you animate, you do. What may cause these multiple calls?
Demo page: http://cornellcoursereview.meteor.com/
My code:
if (Meteor.isServer) {
SearchSource.defineSource('courses', function(searchText, options) {
var options = {
fields: {'catalog':1, 'titleLong':1, 'catalogNbr':1},
limit: 10
};
if(searchText) {
var regExp = buildRegExp(searchText);
var selector = {$or: [
{titleLong: { $regex: regExp } },
{catalog: { $regex: regExp } },
{catalogNbr: { $regex: regExp } }
]}
return Courses.find(selector, options).fetch();
} else {
console.log("couldn't find anything that suits the query");
console.log("query:", searchText);
return Courses.find({}, options).fetch();
}
});
function buildRegExp(searchText) {
var words = searchText.trim().split(/[ \-\:]+/);
var exps = _.map(words, function(word) {
return "(?=.*" + word + ")";
});
var fullExp = exps.join('') + ".+";
return new RegExp(fullExp, "i");
}
}
query = "intro algo" matches with "introduction to analysis of algorithms"
If you go to the demo url, you will see that although the document is found, it's rendered in a weird way.
Type into algo
first, then press any function key like alt
, cmd
, or ctrl
. You will see that the result disappears and appears intermittently.
Set breakpoints inside getData()
and you will see that it returns an empty object even though there's fetch data.
Hi,
I am trying to use Searchsource in my Meteor Angular project.
The implementation as I used to do it in my meteor only project with Blaze seems to work, however on page load I get this error message:
Exception in delivering result of invoking 'search.source': TypeError: Cannot read property 'data' of undefined
My code:
angular.module( 'myapp' ).controller 'feedListCtrl',
($scope, $meteor, $state , $stateParams ) ->
feedName = $stateParams.term
limit = 30
sort =
'publishedDate': -1
$scope.channelData = null
$scope.episodes = null
$scope.channelLoading = true
$scope.episodeCount = 0
$scope.activeListItem = null
$scope.channel = $meteor.subscribe( 'channelMetaByName', feedName )
$scope.feed = $meteor.subscribe( 'feedsByChannelName', feedName, sort )
# $scope.feed = $meteor.collection( Feeds, false ).subscribe( 'feedsByChannelName', feedName, sort )
# $scope.channel = $meteor.collection( Channels, false ).subscribe( 'channelMetaByName', feedName )
$scope.channel.then ( subscription )->
$scope.channelLoading = false
$scope.channelData = Channels.findOne().channelMeta
$scope.feed.then ( subscription ) ->
$scope.episodes = Feeds.find().fetch()
$scope.episodeCount = Feeds.find().count()
$meteor.autorun $scope, ->
console.log("search", $scope.getReactively( 'search' ) )
FeedSearch.search $scope.getReactively( 'search' )
Besides the error message, the search does work in the autorun part. When I call getData I do get the filtered results.
Any idea what is going wrong?
I only get an error message that a secure connection cannot be established.
Is it possible to search on denormalized date, for example cities and then show me the parent documents, or even better search on both ?
thanks in advance..
If I use this transform function for highlighting search results:
transform: function(matchText, regExp) {
console.log(matchText, regExp);
return matchText.replace(regExp, "<b>$&</b>");
},
And I use '_id' as one of the search fields, I get the following error when I search:
Exception in template helper: Error: transformed document can't have different _id
at wrapped [as _transform] (http://localhost:3000/packages/minimongo.js?hash=9b1463853801ce7302ecca3eac339c514a0341db:1174:15)
at http://localhost:3000/packages/minimongo.js?hash=9b1463853801ce7302ecca3eac339c514a0341db:200:18
at Array.forEach (native)
at Function._.each._.forEach (http://localhost:3000/packages/underscore.js?hash=8de51f9d86e95ae2ffee15a8db324a1decccba3e:139:11)
at LocalCollection.Cursor.forEach (http://localhost:3000/packages/minimongo.js?hash=9b1463853801ce7302ecca3eac339c514a0341db:195:5)
at LocalCollection.Cursor.fetch (http://localhost:3000/packages/minimongo.js?hash=9b1463853801ce7302ecca3eac339c514a0341db:238:8)
at SearchSource.getData (http://localhost:3000/packages/meteorhacks_search-source.js?hash=0b4c91bf433d5d896a2beba7db436da54fc8f842:184:17)
at Object.invoices (http://localhost:3000/app/app.js?hash=476b27c1277f65d46aa8bc18f3c3d4243f7322ec:1049:45)
at http://localhost:3000/packages/blaze.js?hash=38069f4f7cfbd8898160bc97d37dd847cd5985fe:2984:16
at http://localhost:3000/packages/blaze.js?hash=38069f4f7cfbd8898160bc97d37dd847cd5985fe:1643:16
Is there any way to get _id searching / transforming to work?
I had an issue getting this package working.
Turns out that when I "meteor add search:source" for some reason the "check" and "ejson" packages were not added.
I'm not sure if this is something I did wrong or how the package is erm packaged!
I'm putting this here for other users who may be facing a similar issue
Can I define an elasticsearch result source?
I've tried with npm elasticsearch plugin but it seems that "body.hits.hits" doesn't match the expecting return type.
you have
Template.searchResult.rendered = function() {
PackageSearch.search('');
};
But when I take this line out, it seems to still work. Is this line helpful? If so, why? (And it should be added to the README if it should be there.)
Package does not return reactive data. I've forked your example app, searched for a particular package, edited the 'packageName' in mongo. The data in the app will not update until I re-query the search.
Please advise.
Is there an API call to clear a search?
Hi, how to search on multiple collection at same time?
I'm getting search-results just every second character I type. It seems to be a problem with rendering because on the server I get results on every character.
Hi,
I posted a question/issue concerning performance of searchsource on a mobile browser searching a client (mini mongo) collection.
The whole post can be found here: https://forums.meteor.com/t/minimongo-mobile-performance/4814
I would be grateful if you could have a read and tell me if I am doing something wrong, if I am pushing the boundaries of the mobile platform or if it is another issue.
Cheers
Matt
I´m triying follow step by step the user guide package but I´m getting the same error. Is my first App, and I don´t have idea what happen but sadly, is not working...
Some suggestion?
Thanks in advance
Exception in delivering result of invoking 'search.source': Error: Internal server error [500]
at .extend.livedata_result (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:4625:23)
at onMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3365:12)
at http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2734:11
at Array.forEach (native)
at Function..each..forEach (http://localhost:3000/packages/underscore.js?46eaedbdeb6e71c82af1b16f51c7da4127d6f285:149:11)
at self.socket.onmessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:2733:11)
at REventTarget.dispatchEvent (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:173:22)
at SockJS._dispatchMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1158:10)
at SockJS._didMessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1216:18)
at WebSocket.that.ws.onmessage (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:1363:17)
The library won't run without check or ejson, so the dependencies should be explicitly declared.
Maybe this is a dumb question, but i saw in the examples there is a transformDoc
property which can be used to modify the docs.
Is there a way to skip this and return a publish function instead?
I have a Collection named post
which has a postThumbnail
property, which is a reference to a document in Files.files
collection. I return every post thumbnail using publishComposite
publication on server, so it will be awesome if instead of returning a cursor, i could specify a named publication, something like:
SearchSource.defineSource('posts', function(searchText, options) {
// ...
return namedPublication('allposts' , searchText , options);
});
Meteor.publishComposite('allposts', function(searchText, options){
return {
find : function(){ return Posts.find(); },
children : [
{
find: function(post){
if (!post.adThumbnail) return;
return Files.files.find({_id:post.adThumbnail});
}
}
]
}
});
I know problem can be solved using transformDoc
but who knows, maybe this is possible.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.