Meteor.js - ways to do user search over multiple c

2020-07-18 10:17发布

问题:

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 !!!

回答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...