3

I'm having a bit of a dilemma concerning how to set up the collections in my Meteor app. The user search bar is a central part of my app, and the user needs to be able to enter one search and have results across several different collections :

user query : 'foo'

var query = 'foo';
var actors_results = Actors.find({ $or : [{ name : query}, { actor_biography : query }] );
var films_results = Films.find({ $or : [{ name : query}, { description : query }] );
var cinemas_results = Cinemas.find({ $or : [{ name : query}, { genres : query }] );

For search results display this is not good - I don't think (???) I can combine these cursors into one cursor, and so simple things like pagination become almost impossible to do (or I don't know how to do it).

The only solution I know would be to make a SuperCollection where I put all of the documents and have a field 'type' which could be 'actor', 'film' or 'cinema', then pagination etc becomes easy.

But it seems to me this really complicates everything else... the structure of the database no longer reflects the data. Actors and Cinemas have nothing in common in terms of data/structure, I just need to be able to search them in parallel.

Also how would I set up multiple validation schemes for the SuperCollection depending on the value of the field 'type' ?

Any ideas/suggestions much appreciated !!!

Petrov
  • 4,200
  • 6
  • 40
  • 61

1 Answers1

1

OK I've worked out a way to do this without re-doing my entire database. Bravo Meteor !

on the server :

Meteor.publish('search_results', function(query){
    if(query){
        var self = this;
        var actors = Actors.find({ $or : [{ name : query}, { actor_biography : query }] ),
        films = Films.find({ $or : [{ name : query}, { actor_biography : query }] ),
        cinemas = Cinemas.find({ $or : [{ name : query}, { actor_biography : query }] );
        actors.forEach(function(doc){
            self.added('search_collection', doc._id, { name : doc.name, type : 'actor' });
        });
        films.forEach(function(doc){
            self.added('search_collection', doc._id, { name : doc.name, type : 'film' });
        });
        cinemas.forEach(function(doc){
            self.added('search_collection', doc._id, { name : doc.name, type : 'cinema' });         
        this.ready();
    } else {
        this.ready();
    }
});

and on the client :

Deps.autorun(function(){
    Meteor.subscribe('search_results', Session.get('currentQuery'));
});

SearchCollection = new Meteor.Collection('search_collection');

Now SearchCollection contains the data I want from the results, where I can decide what data I want from each collection separately.

One disadvantage is that I'm clearly duplicating data - some if not all of these records exist on the client already...

Petrov
  • 4,200
  • 6
  • 40
  • 61
  • 2
    Why not try the new easy-search atmosphere package. https://github.com/matteodem/meteor-easy-search – Warz Dec 14 '13 at 06:14
  • 2
    thanks @Warz for the tip - I've not much text in my fields, more like key value pairs, so I think elastic search might be a bit overkill. On the subject, Mongo's new full-text search is also worth a look for those in need of a heftier text search – Petrov Dec 15 '13 at 19:18
  • @Warz is easy-search supporting search over multiple collection? Any examples how to do that? – Jaro May 19 '15 at 07:52
  • 1
    @Jaro there are lots of examples with that package and yes you can query over multiple collections. http://matteodem.github.io/meteor-easy-search/docs/blaze-components/ – Warz May 19 '15 at 16:53
  • Ok. Now I found the examples and agree with @Warz that easy-search is probably easier way to do this. – Jaro May 19 '15 at 17:15