问题
I have a collection Songs which contains data in the following format:
{artist:"Dream Theater", title: "Pull me under"}, {artist:"Dream Theater", title: "Finally free"}
I am using the package mizzao-autocomplete There are more than 5000 entries, so I definetely need server-side autocompletion. On server I published the collection:
Meteor.publish("autocompleteArtists", function(selector, options) {
Autocomplete.publishCursor(Songs.find(selector, options), this);
this.ready();
});
Client subscription looks like:
Template.home.helpers({
settings: function() {
return {
position: "top",
limit: 5,
rules: [{
collection: 'Songs',
subscription: 'autocompleteArtists',
field: "artist",
template: Template.songItem
}]
};
}
});
Should I have both collection and subscription in the settings() function?
Last part, the client template:
{{> inputAutocomplete settings=settings id="artistInput" type="text" placeholder="Artist" length="20"}}
My purpose is to look for an artist and when I select it, to subscribe to a simple server publish which returns all songs belonging to that artist. The thing is, if I have multiple entries with the same artist, of course, the list of results is showing the artist multiple times. I would need to to somehow a "distinct" publish which would return all artists, but there's no such a feature in Meteor. I found some things implementing the aggregation and distinct, but I don't see how to use Autocomplete publishCursor function... My temporary solution was to denormalize and add a Artists collection, but I should not do that.
Is there a simpler way?
回答1:
It appears you need both the subscription
and the collection
argument if you want to do the autocomplete on the server.
Unfortunately, as you've noticed, there's not really a good way to enforce uniqueness. You can play around with aggregation, but unless it returns a cursor, it doesn't look like that's what you want (and, e.g., Meteorhacks:aggregate does not).
One (simple?) way around this is to identify a single instance of every artist and flag it (autocomplete: true
); then you can use the filter
option to filter where autocomplete = true. This is really easy to do if people are manually entering songs:
Meteor.methods({
insertSong: function(song, artist) {
var entry = {title: song, artist: artist, autocomplete: false};
if (Songs.find({artist: artist}).count() === 0) { entry.autocomplete = true; }
Songs.insert(entry);
}
});
Your rules
then just needs to include a filter
object:
...
rules: [{
collection: 'Songs',
subscription: 'autocompleteArtists',
field: "artist",
template: Template.songItem,
filter: {autocomplete: true}
}]
...
You'll then need another pub / sub to actually display the songs from the artist in question:
// Server
Meteor.publish("songsByArtist", function(artist) {
return Songs.find({artist: artist});
});
// Client
Template.home.events({ // listen for selection and subscribe
"autocompleteselect input": function(event, template, doc) {
Meteor.subscribe("songsByArtist", doc.artist);
}
});
// And you can iterate like so with a helper:
songsToDisplay: function() {
return Songs.find();
}
<!-- HTML -->
{{#each songsToDisplay}}
{{> songAndArtist}}
{{/each}}
You can play around with it on this MeteorPad. Sorry I can't think of a better way.
来源:https://stackoverflow.com/questions/30027668/meteor-autocomplete-with-distinct-feature