使用Meteor建模和发布基于跟随者的提要

使用Meteor建模和发布基于跟随者的提要,meteor,meteor-publications,database,nosql,Meteor,Meteor Publications,Database,Nosql,我正在开发一个简单的应用程序,用户可以跟随其他用户。用户可以发布明星帖子。用户的提要由他们关注的用户所发布的帖子组成。其实很简单。然而,这一切在Mongo和Meteor中变得复杂 基本上,我可以想到两种建模方法: 用户有一个属性,following,它是用户遵循的用户标识数组。此外,一篇文章还有一个属性,starers,它是一个为这篇文章加上星号的用户ID数组。这种方法的优点是出版物相对简单: Meteor.publish 'feed', (limit) -> Posts.find({

我正在开发一个简单的应用程序,用户可以跟随其他用户。用户可以发布明星帖子。用户的提要由他们关注的用户所发布的帖子组成。其实很简单。然而,这一切在Mongo和Meteor中变得复杂

基本上,我可以想到两种建模方法:

  • 用户有一个属性,
    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});
    });