使用Meteor建模和发布基于跟随者的提要
我正在开发一个简单的应用程序,用户可以跟随其他用户。用户可以发布明星帖子。用户的提要由他们关注的用户所发布的帖子组成。其实很简单。然而,这一切在Mongo和Meteor中变得复杂 基本上,我可以想到两种建模方法:使用Meteor建模和发布基于跟随者的提要,meteor,meteor-publications,database,nosql,Meteor,Meteor Publications,Database,Nosql,我正在开发一个简单的应用程序,用户可以跟随其他用户。用户可以发布明星帖子。用户的提要由他们关注的用户所发布的帖子组成。其实很简单。然而,这一切在Mongo和Meteor中变得复杂 基本上,我可以想到两种建模方法: 用户有一个属性,following,它是用户遵循的用户标识数组。此外,一篇文章还有一个属性,starers,它是一个为这篇文章加上星号的用户ID数组。这种方法的优点是出版物相对简单: Meteor.publish 'feed', (limit) -> Posts.find({
following
,它是用户遵循的用户标识数组。此外,一篇文章还有一个属性,starers
,它是一个为这篇文章加上星号的用户ID数组。这种方法的优点是出版物相对简单:
Meteor.publish 'feed', (limit) ->
Posts.find({starrers: {$in: Meteor.users.findOne(@userId).following}}, {sort: {date: -1}, limit:limit})
我们不会被动地倾听用户在跟踪谁,但现在这还不算太糟。这种方法的主要问题是:(1)如果有1000000人担任一个职位的明星,那么单个文档将变得庞大且效率低下。另一个问题是(2)跟踪信息是件痛苦的事情,比如当一个用户开始跟踪另一个用户,或者当一个用户在帖子上加了星Stars
和Follows
。如果一个用户在一篇文章中起了作用,那么我们将创建一个具有属性userId
和postId
的文档。如果一个用户跟随另一个用户,那么我们将创建一个具有属性userId
和followId
的文档。这为用户
和帖子
提供了较小文档大小的优势,但在查询时会变得复杂,特别是因为Mongo不处理连接# a helper to handle stopping observeChanges
observer = (sub, func) ->
handle = null
sub.onStop ->
handle?.stop?()
() ->
handle?.stop?()
handle = func()
Meteor.publish 'feed', (limit) ->
sub = this
userId = @userId
followIds = null
eventIds = null
publishFollows = observer sub, () ->
followIds = {}
Follows.find({userId:userId}).observeChanges
added: (id, doc) ->
followIds[id] = doc.followId
sub.added('follows', id, doc)
publishStars()
removed: (id) ->
delete followIds[id]
sub.removed('follows', id)
publishStars()
publishStars = observer sub, () ->
eventIds = {}
Stars.find({userId: {$in: _.keys(followIds)}).observeChanges
added: (id, doc) ->
eventIds[id] = null
sub.added('stars', id, doc)
publishEvents()
removed: (id) ->
delete eventIds[id]
sub.removed('stars', id)
publishEvents()
publishEvents = observer sub, () ->
Events.find({_id: {$in: _.keys(eventIds)}}, {sort: {name:1, date:-1}, limit:limit}).observeChanges
added: (id, doc) ->
sub.added('events', id, doc)
changed: (id, fields) ->
sub.changed('events', id, fields)
removed: (id) ->
sub.removed('events', id)
虽然这是可行的,但在规模上似乎非常有限。特别是,我们必须编制一份名单,列出每一位追随者的每一篇明星文章。该列表的大小将快速增长。然后我们对所有帖子执行一个巨大的$in
查询
另一个麻烦是在我们订阅后在客户端上查询提要:
Meteor.subscribe("feed", 20)
posts = null
Tracker.autorun ->
followers = _.pluck(Follows.find({userId: Meteor.userId()}).fetch(), "followId")
starredPostIds = _.pluck(Stars.find({userId: {$in: followers}}).fetch(), "postId")
posts = Posts.find({_id: {$in: starredPostIds}}, {sort: {date: -1}, limit: 20}).fetch()
就像我们做了两次这样的工作。首先,我们在服务器上完成发布提要的所有工作。然后我们需要在客户端上再次执行完全相同的逻辑来获取这些帖子
我这里的问题是一个设计高于一切的问题如何根据帖子有效地设计此提要?我应该使用什么集合/集合模式?我应该如何创建适当的出版物?如何在客户机上查询提要?因此,Mongo和“非关系”数据库根本不是为关系数据设计的。因此,Mongo在这里没有解决方案。我最终使用了Neo4j,但SQL也可以正常工作。meteor add reywood:publish composite
Meteor.publishComposite('tweets', function(username) {
return {
find: function() {
// Find the current user's following users
return Relationships.find({ follower: username });
},
children: [{
find: function(relationship) {
// Find tweets from followed users
return Tweets.find({user: relationship.following});
}
}]
}
});
Meteor.publish('ownTweets', function(username) {
return Tweets.find({user: username});
});