meteorhacks / search-source

Reactive Data Source for Search
MIT License
146 stars 33 forks source link

Client side search? #3

Open fardeem opened 9 years ago

fardeem commented 9 years ago

I have the data source on the client side. How can I use that?

arunoda commented 9 years ago

That's not supported at the moment. But that's a good idea. May be we should allow to define the data source in the client. On Mon Jan 12 2015 at 4:06:48 PM Fardeem Munir notifications@github.com wrote:

I have the data source on the client side. How can I use that?

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3.

fardeem commented 9 years ago

Yeah, make it available client side

On Mon, Jan 12, 2015 at 4:43 PM, Arunoda Susiripala < notifications@github.com> wrote:

That's not supported at the moment. But that's a good idea. May be we should allow to define the data source in the client. On Mon Jan 12 2015 at 4:06:48 PM Fardeem Munir notifications@github.com wrote:

I have the data source on the client side. How can I use that?

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3.

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-69552946 .

Fardeem Munir www.erubai.com @awesomerubai

arunoda commented 9 years ago

I have add this feature. See: https://github.com/meteorhacks/search-source#defining-data-source-in-the-client

Hope this is what you wanted

shkomg commented 9 years ago

Hi, Arunoda,

thank you for the awesome package. May you, please, provide working example for client search at https://github.com/meteorhacks-samples/meteor-instant-search-demo ?

Thank you.

arunoda commented 9 years ago

Check here: http://instant-search-demo.meteor.com/

On Mon Feb 16 2015 at 2:56:48 PM shkomg notifications@github.com wrote:

Hi, Arunoda,

thank you for the awesome package. May you, please, provide working example for client search at https://github.com/meteorhacks-samples/meteor-instant-search-demo ?

Thank you.

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-74479989 .

shkomg commented 9 years ago

Well, I can't find there anything defining data source in the client like .fetchData May, you, pls, point me?

Thank you.

arunoda commented 9 years ago

Ah nope. It's not there. I don't think I've a working example now.

On Mon Feb 16 2015 at 3:32:59 PM shkomg notifications@github.com wrote:

Well, I can't find there anything defining data source in the client like .fetchData May, you, pls, point me?

Thank you.

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-74484434 .

shkomg commented 9 years ago

:( that 'd be awesome to have such an example.

may you, pls, point me quick on how I may use .fetchData? should it go before .getData?

As I do have reactive data source on client changing over some filters. So I need to adjust data source according to session var stage.

Chos89 commented 9 years ago

hey shkomg, did you manage to get .fetchData to work, any working examples?

shkomg commented 9 years ago

yep, I just 've written my own solution. That was quicker & simplier for my case.

2015-03-18 19:43 GMT+02:00 Chos89 notifications@github.com:

hey shkomg, did you manage to get .fetchData to work, any working examples?

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-83083016 .

Best regards

Serhiy Khvashchuk

Chos89 commented 9 years ago

Could you give any hints or code snippets on how did you do it?

shkomg commented 9 years ago

well, that's pretty simple:

I have 1st template with <input type="text" id="search-box" placeholder="type search text here">

For the 1st template I have a keyup event on search box which creates session with search text.

And for 2nd template I provide search results based on this session data.

Does it makes sense?

2015-03-18 20:24 GMT+02:00 Chos89 notifications@github.com:

Could you give any hints or code snippets on how did you do it? You can email me on i.josip89@gmail.com if it's outside of scope of this package...

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-83110513 .

Best regards

Serhiy Khvashchuk

Chos89 commented 9 years ago

I think I understand what you are doing, but not sure if this would work in my case, thanks anyway.

2015-03-18 19:50 GMT+01:00 shkomg notifications@github.com:

well, that's pretty simple:

I have 1st template with <input type="text" id="search-box" placeholder="type search text here">

For the 1st template I have a keyup event on search box which creates session with search text.

And for 2nd template I provide search results based on this session data.

Does it makes sense?

2015-03-18 20:24 GMT+02:00 Chos89 notifications@github.com:

Could you give any hints or code snippets on how did you do it? You can email me on i.josip89@gmail.com if it's outside of scope of this package...

— Reply to this email directly or view it on GitHub < https://github.com/meteorhacks/search-source/issues/3#issuecomment-83110513

.

Best regards

Serhiy Khvashchuk

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-83119246 .

sbking commented 9 years ago

It would be nice if we could use this with a REST API data source on the client. The particular REST API I'm using has a rate limit per second per IP address, so it is not feasible to do the requests on the server.

mattiLeBlanc commented 9 years ago

Hi, I am current using the client side search too, getting my results from an external API and loading it in a subscription like this (client side):

 Meteor.call( 'getFeedContent', Session.get( 'feed' ).url, ( error, result ) ->
            if result
                instance.channel.set( result )

                handle = Meteor.subscribe( 'episodes', result.episodes )
                instance.autorun( ( c )->

                    # searchHandle = Meteor.subscribe( 'episodes', result.episodes )

                    if handle.ready()
                        console.log("eps", Episodes.find({}).count())
                        console.log("handle ready!")
                        EpisodesSearch.search( '' )
                        c.stop()
                )
            else
                console.error error
            instance.loading.set( false )

        )

On the server I have a publication named 'episodes' which get filled by the subscription and uses instance.added( 'episodes', Random.id() to populate the client collection.

Then finally I have a client side collection SearchSource declaration:

 if Meteor.isClient
    @Episodes = new Meteor.Collection( 'episodes' )
    options =
        keepHistory: 0
        localSearch: false

    fields = ['title']
    @EpisodesSearch = new SearchSource( 'episodes', fields, options )

    buildRegExp = ( searchText ) ->
        parts = searchText.trim().split(/[ \-\:]+/)
        return new RegExp("(" + parts.join('|') + ")", "ig")

    # set up client datasource
    EpisodesSearch.fetchData = (searchText, options, success) ->
        err         = null
        options     = {sort: { 'publishedDate': -1 }, limit: 20}
        if searchText
            # get rid of surrounding spaces
            searchText  = searchText.trim()
            selector    =
                title:  buildRegExp( searchText )
            console.log(selector)
            data = Episodes.find( selector, options ).fetch()
        else
            data = Episodes.find({}, options).fetch()
        # return result
        success(err, data)

Now I have the following weird issue, that when I do a search on one episode and then clear my search box again, the one episode episode result of the previous search is at the top of the new search result list.

I can do it all in my Chrome console. After page render, 20 episodes are loaded ordered by date desc. Then when I do EpisodesSearch.search('trash') it results one episode titled 'trash'. Then when I run EpisodesSearch.search('') it shows me 20 episodes, of which no 1 is Trash. Number 2 is the actual newest episode that was on top. I am not using history and calling cleanHistory doesn't do anything. Also when I do Episodes.find({}).fetch(), it still shows the original master list of episodes. From this I deduce that SearchSearch has its own cache that is use not being refreshed.

Can anyone confirm this or tell me what I do wrong?

Chos89 commented 9 years ago

Check that your data doesnt have the same date On Apr 26, 2015 12:30 PM, "mattiLeBlanc" notifications@github.com wrote:

Hi, I am current using the client side search too, getting my results from an external API and loading it in a subscription like this (client side):

Meteor.call( 'getFeedContent', Session.get( 'feed' ).url, ( error, result ) -> if result instance.channel.set( result )

            handle = Meteor.subscribe( 'episodes', result.episodes )
            instance.autorun( ( c )->

                # searchHandle = Meteor.subscribe( 'episodes', result.episodes )

                if handle.ready()
                    console.log("eps", Episodes.find({}).count())
                    console.log("handle ready!")
                    EpisodesSearch.search( '' )
                    c.stop()
            )
        else
            console.error error
        instance.loading.set( false )

    )

On the server I have a publication named 'episodes' which get filled by the subscription count and uses . instance.added( 'episodes', Random.id() to populate the client collection.

The finally I have a client side collection SearchSource declaration:

if Meteor.isClient @Episodes = new Meteor.Collection( 'episodes' ) options = keepHistory: 0 localSearch: false

fields = ['title']
@EpisodesSearch = new SearchSource( 'episodes', fields, options )

buildRegExp = ( searchText ) ->
    parts = searchText.trim().split(/[ \-\:]+/)
    return new RegExp("(" + parts.join('|') + ")", "ig")

# set up client datasource
EpisodesSearch.fetchData = (searchText, options, success) ->
    err         = null
    options     = {sort: { 'publishedDate': -1 }, limit: 20}
    if searchText
        # get rid of surrounding spaces
        searchText  = searchText.trim()
        selector    =
            title:  buildRegExp( searchText )
        console.log(selector)
        data = Episodes.find( selector, options ).fetch()
    else
        data = Episodes.find({}, options).fetch()
    # return result
    success(err, data)

Now I have the following weird issue, that when I do a search on a one episode and then clear my search box again the one episode of the previous search is there at the top of the result list.

I can do it all in my Chrome console. After page render, 20 episodes are loaded ordered by data desc. Then when I do EpisodesSearch.search('trash') it results one episode titled trash. Then when I run EpisodesSearch.search('') it shows me 20 episodes, of which no 1 is Trash. Number 2 is the actual newest episode that was on top. I am not using history and calling cleanHistory doesnt work. Also when I do Episodes.find({}).fetch() is still shows the original master list of episodes. From this I deduce that SearchSearch has its on cache that is not cleared.

Can anyone confirm this or tell me what I do wrong?

— Reply to this email directly or view it on GitHub https://github.com/meteorhacks/search-source/issues/3#issuecomment-96361353 .

mattiLeBlanc commented 9 years ago

What do you mean with "Check if data doesn't have the same date". Where can I find this 'date'? I am looking at the EpisodeSearch object but can't find any date. As far as I know I am doing a new search so I don't understand why the previous result is being added on top.

mattiLeBlanc commented 9 years ago

I debugged the FetchData function just before the Success hits (cause there the data is correct), and this is the function where the local storage is updated

SearchSource.prototype._updateStore = function(data) {
  var self = this;
  var storeIds = _.pluck(this.store.find().fetch(), "_id");
  var currentIds = [];
  data.forEach(function(item) {
    currentIds.push(item._id);
    self.store.update(item._id, item, {upsert: true});
  });

  var removedItem = _.difference(storeIds, currentIds);
  removedItem.forEach(function(id) {
    self.store.remove(id);
  });
};

The actual problem is that the episode Trash, is normally the 9 results in the first list of 20. When I search for Trash, it becomes the only result. When I clear the searchbox, Trash is the one result out of the 20 displayed, while it has an older publish date and should be in position 9. So I guess, it is an ordering issue.

In the update store function:

  data.forEach(function(item) {
    currentIds.push(item._id);
    self.store.update(item._id, item, {upsert: true});
  });
  var removedItem = _.difference(storeIds, currentIds);
  removedItem.forEach(function(id) {
    self.store.remove(id);
  });

the removedItem array is empty because the storeIds will hold the 'Trash' entry and the currentIds will hold the 20 items (including the Trash entry), so nothing is removed. So a couple of lines above where the upsert was executed, the Trash entry was already added in the previous search process, so when the 20 entries are stored I think the Trash entry is not added in on the 9th position because it was already there and will be before the new entries. That is why it is on position 1 instead of it's original position 9.

So I guess I know what is happening now, however I don't know how to proceed next.

Do I need to sort the result again in the Helper to get the right order? Seems a bit like a hack. The real issue is the that FetchDate doesn't return the dataset according to the sort instructions that where provided.

Could this be fixed?

mattiLeBlanc commented 9 years ago

Adding the sort in the GetData fixes it for me:

episodes: ->
        instance = Template.instance()
        data = EpisodesSearch.getData(
            sort: {'publishedDate': -1}
            limit: 30
        )
        return data

so not sure if it was a bug or just me being silly.

One thing I found out that it is imperative that I stop the Autorun for the handle that subscribes the episode. If i don't do that it is really messing up the collection.