1

I'm currently creating a research engine for my app.

Until now, I used Publish composite + iron router : The user could had filters to search for some specific set of users.

Now, I want him to be able to look for some keywords too. For that I downloaded and tested the great SearchSource package.

The problem is that the SearchSource server side definition only seems to allow to return one cursor.

How could I combine the two logics ? Even if it's tricky, please, share.

Of course I could make an autorunned subscription where I look for every users loaded on the client and then subscribe to the additionnal documents, but it is not really the most performant and beautifull thing to do.

Some data :

Here is my current Publish Composite for filters :

Meteor.publishComposite("findTalkers", function(page, langs){
        //console.log("Find Talkers");
        //console.log("page : " + page);
        //console.log("langs : " + langs);
        if (langs.length)
        {
            return ({
                find: function()
                {
                    if (langs && langs.length)
                    {
                        var test = {$in: langs};
                                preSelectedUsers = [],
                                selector = {
                                    _id: {$ne: this.userId},
                                    "profile.completed": true,
                                    "profile.firstName": {$exists: true},
                                    "profile.languages.native": {$exists: false},
                                    "profile.languages.lang": test
                                };
                        Counts.publish(this, "nbUsers", Meteor.users.find(selector, {
                            fields: {_id: 1}
                        }), {noReady: false,    nonReactive: true});
                        if (page > 1)
                        {
                            preSelectedUsers = Meteor.users.find(selector, {
                                sort: {'profile.talkname': 1},
                                limit: 25,
                                skip: (25 * (page || 1)),
                                fields: {_id: 1}
                            }).fetch();
                            var i = -1;
                            while (preSelectedUsers[++i])
                                preSelectedUsers[i] = preSelectedUsers[i]._id;
                        }
                        if (page > 1)
                            selector._id = {$in: preSelectedUsers};
                        return Meteor.users.find(selector, {
                            fields: userFields,
                            sort: {'profile.talkname': 1},
                            limit: 25
                        });
                    }
                },
                children: [
                    {
                        // Finding user's profile picture if it is not url
                        find: function(user)
                        {
                            if (user && user.profile && user.profile.avatar.type != "url")
                                return Images.find({_id: user.profile.avatar.data}, {sort: {uploadedAt: -1}, limit: 1});
                        }
                    }
                ]
            });
        }
        else
        {
            return ({
                find: function()
                {
                    return Meteor.users.find({_id: "flush"});
                }
            });
        }
    });

Here is my research with SearchSource :

Client :

var searchOptions = {
      keepHistory: 1000 * 60 * 5,
      localSearch: true
    },

    SearchSources = {
      talkersSearch: new SearchSource('users', ['profile.talkname'], searchOptions)
    };

Router.map(function(){
      this.route('talkers/:page?',
      {
        template: "talkers",
        onBeforeAction: function(pause){
          (Meteor.user() && Meteor.user().profile.completed)
              ? this.next()
              : this.render('/profile');
        },
        waitOn: function(){
          var filters = MatesFilter.find().fetch(),
              i = -1;
          while (filters[++i])
            filters[i] = filters[i].value;
          if (filters.length)
          {
            return Meteor.subscribe("findTalkers", (this.params.page || 1), filters, function(){
              Session.set('numberuser', Counts.get("nbUsers"));
            });
          }
          return Meteor.subscribe('myself');
        }
      });
}

Template.talkers.helpers({
  getPackages: function() {
    return SearchSources.talkersSearch.getData({
      transform: function(matchText, regExp) {
        return matchText.replace(regExp, "<b>$&</b>")
      },
      sort: {isoScore: -1}
    });
  }
}

Template.talkers.events({
  "keyup #header-search": _.throttle(function(e) {
    Session.set("matesSearch", $(e.target).val().trim());
    console.log("Searching for : " + text);
SearchSources.talkersSearch.search(Session.get("matesSearch"), {
          page: (this.params.page || 1),
          filters: filters
        });
  }, 200)
}

SERVER :

SearchSource.defineSource('users', function(searchText, options) {
  var options = {sort: {"profile.talkname": -1}, limit: 25};

  if(searchText)
  {
    var regExp = buildRegExp(searchText);
        selector = { $or: [
          { "profile.talkname": regExp },
          { "profile.bio":      regExp }
        ] };

    return Meteor.users.find(selector, options).fetch();
  }
  return ;
});

All this Gives me two sources from which I can get users. I'd want to get a mean to merge the two ides (a composition of publication INSIDE the search, for example).

Thanks you.

David Panart
  • 656
  • 6
  • 20
  • Could you post the relevant MCVE? As it stands it's fairly hard to know what you're talking about (I do have no knowledge of the libs you use though). Some code would help see what you have achieved, and what you want to achieve. – Kyll Aug 27 '15 at 10:57

0 Answers0