我在Meteor中遇到了一个非常简单的场景:
我收集了很多字段,其中一些字段包含很多字段。
我想创建一个搜索该集合的页面。
该集合中每件商品的其中一个字段是"类别"。
我想让用户按该类别进行过滤。
为此,我需要只发布集合中类别字段的不同值。
我无法找到一种方法来做到这一点,而不会发布太长时间的整个集合。如何只发布不同的类别并使用它们来填充下拉列表?
奖金问题并且有些相关:如何在不发布整个集合的情况下发布集合中所有项目的计数?
答案 0 :(得分:1)
使这更容易的一个好的起点是将categories
规范化为单独的数据库集合。
然而,假设这是不可能或不实际的,最好的(虽然不完美)解决方案是发布集合的两个单独版本,一个只返回整个集合的categories
字段,另一个返回所有仅适用于所选类别的集合的字段。这看起来如下:
// SERVER
Meteor.startup(function(){
Meteor.publish('allThings', function() {
// return only id and categories field for all your things
return Things.find({}, {fields: {categories: 1}});
});
Meteor.publish('thingsByCategory', function(category) {
// return all fields for things having the selected category
// you can then subscribe via something like a client-side Session variable
// e.g., Meteor.subscribe("thingsByCategory", Session.get("category"));
return Things.find({category: category});
});
});
请注意,您仍然需要从Things光标组装客户端类别数组(例如,通过使用下划线的_.pluck和_.uniq方法来获取类别并删除任何重复项)。但是,由于您现在只使用单字段文档,因此数据集会小得多。
(注意,理想情况下,您希望在发布函数中使用Mongo的distinct()方法仅发布不同的类别,但这不可能直接,因为它返回一个无法发布的数组)。
答案 1 :(得分:0)
您可以使用内部this._documents.collectionName
仅将新类别发送到客户端。跟踪要删除的类别会变得有点难看,因此您最终可能最终会维护单独的“类别”集合。
示例:
Meteor.publish( 'categories', function(){
var self = this;
largeCollection.find({},{fields: {category: 1}).observeChanges({
added: function( id, doc ){
if( ! self._documents.categories[ doc.category ] )
self.added( 'categories', doc.category, {category: doc.category});
},
removed: function(){
_.keys( self._documents.categories ).forEach( category ){
if ( largeCollection.find({category: category},{limit: 1}).count() === 0 )
self.removed( 'categories', category );
}
}
});
self.ready();
};
答案 2 :(得分:0)
答案 3 :(得分:-1)
这些模式可能对您有所帮助。这是一份发布计数的出版物:
/*****************************************************************************/
/* Counts Publish Function
/*****************************************************************************/
// server: publish the current size of a collection
Meteor.publish("countsByProject", function (arguments) {
var self = this;
if (this.userId) {
var roles = Meteor.users.findOne({_id : this.userId}).roles;
if ( _.contains(roles, arguments.projectId) ) {
//check(arguments.video_id, Integer);
// observeChanges only returns after the initial `added` callbacks
// have run. Until then, we don't want to send a lot of
// `self.changed()` messages - hence tracking the
// `initializing` state.
Videos.find({'projectId': arguments.projectId}).forEach(function (video) {
var count = 0;
var initializing = true;
var video_id = video.video_id;
var handle = Observations.find({video_id: video_id}).observeChanges({
added: function (id) {
//console.log(video._id);
count++;
if (!initializing)
self.changed("counts", video_id, {'video_id': video_id, 'observations': count});
},
removed: function (id) {
count--;
self.changed("counts", video_id, {'video_id': video_id, 'observations': count});
}
// don't care about changed
});
// Instead, we'll send one `self.added()` message right after
// observeChanges has returned, and mark the subscription as
// ready.
initializing = false;
self.added("counts", video_id, {'video_id': video_id, 'observations': count});
self.ready();
// Stop observing the cursor when client unsubs.
// Stopping a subscription automatically takes
// care of sending the client any removed messages.
self.onStop(function () {
handle.stop();
});
}); // Videos forEach
} //if _.contains
} // if userId
return this.ready();
});
这是一个从特定领域创建新集合的人:
/*****************************************************************************/
/* Tags Publish Functions
/*****************************************************************************/
// server: publish the current size of a collection
Meteor.publish("tags", function (arguments) {
var self = this;
if (this.userId) {
var roles = Meteor.users.findOne({_id : this.userId}).roles;
if ( _.contains(roles, arguments.projectId) ) {
var observations, tags, initializing, projectId;
initializing = true;
projectId = arguments.projectId;
observations = Observations.find({'projectId' : projectId}, {fields: {tags: 1}}).fetch();
tags = _.pluck(observations, 'tags');
tags = _.flatten(tags);
tags = _.uniq(tags);
var handle = Observations.find({'projectId': projectId}, {fields : {'tags' : 1}}).observeChanges({
added: function (id, fields) {
if (!initializing) {
tags = _.union(tags, fields.tags);
self.changed("tags", projectId, {'projectId': projectId, 'tags': tags});
}
},
removed: function (id) {
self.changed("tags", projectId, {'projectId': projectId, 'tags': tags});
}
});
initializing = false;
self.added("tags", projectId, {'projectId': projectId, 'tags': tags});
self.ready();
self.onStop(function () {
handle.stop();
});
} //if _.contains
} // if userId
return self.ready();
});
答案 4 :(得分:-1)
我没有在Meteor上测试它,根据回复,我对它会起作用持怀疑态度,但使用mongoDB distinct会有所帮助。
http://docs.mongodb.org/manual/reference/method/db.collection.distinct/