3

ユーザーが他のユーザーをフォローできるシンプルなアプリに取り組んでいます。ユーザーは投稿にスタ​​ーを付けることができます。また、ユーザーのフィードは、フォローしているユーザーがスターを付けた投稿で構成されます。実際にはかなり単純です。ただし、これはすべて Mongo と Meteor では複雑になります...

私が考えることができるこれをモデル化する基本的に2つの方法があります:

  1. ユーザーには、ユーザーがfollowingフォローする userIds の配列であるプロパティがあります。また、投稿には、starrersこの投稿にスタ​​ーを付けた userId の配列であるプロパティがあります。この方法の良い点は、出版物が比較的単純であることです。

    Meteor.publish 'feed', (limit) ->
      Posts.find({starrers: {$in: Meteor.users.findOne(@userId).following}}, {sort: {date: -1}, limit:limit})
    

    ユーザーが誰をフォローしているかを反応的に聞いているわけではありませんが、今のところそれほど悪くはありません。このアプローチの主な問題は、(1) 1000000 人が投稿にスタ​​ーを付けると、個々のドキュメントが大きくなり、非効率になることです。もう 1 つの問題は、(2) ユーザーが別のユーザーをフォローし始めた時期や、ユーザーが投稿にスタ​​ーを付けた時期などの情報を追跡するのが面倒なことです。

  2. これを行うもう 1 つの方法は、さらに 2 つのコレクションを作成することStarsですFollows。ユーザーが投稿にスタ​​ーを付けると、プロパティuserIdとを含むドキュメントが作成されますpostId。ユーザーが別のユーザーをフォローしている場合、プロパティuserIdとを持つドキュメントを作成しますfollowIdUsersこれにより、とのドキュメント サイズが小さくなるという利点が得られますPostsが、特に Mongo は結合を処理しないため、クエリに関しては複雑になります。

さて、私はいくつかの調査を行いましたが、人々は2番目の選択肢が正しい方法であることに同意しているようです. 今私が抱えている問題は、効率的なクエリと公開です。Advanced Publications に関する Discover Meteor の章に基づいて、ユーザーのフォロワーがスターを付けた投稿を並べ替えて限定して公開する出版物を作成しました。

# 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すべての投稿に対して巨大なクエリを実行します。

もう 1 つの厄介な点は、サブスクライブした後にクライアントでフィードをクエリすることです。

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()

この作業をすべて 2 回行っているようなものです。まず、フィードを公開するためにサーバー上ですべての作業を行います。次に、クライアントでまったく同じロジックを実行して、それらの投稿を取得する必要があります...

ここでの私の質問は、すべての設計の問題です。投稿を凝視しているフォロワーに基づいて、このフィードを効率的に設計するにはどうすればよいですか? どのコレクション/コレクション スキーマを使用すればよいですか? 適切なパブリケーションを作成するにはどうすればよいですか? クライアントでフィードを照会するにはどうすればよいですか?

4

2 に答える 2

0

したがって、Mongo と「非リレーショナル」データベースは、リレーショナル データ用に設計されていないことがわかります。したがって、Mongo では解決策はありません。最終的に Neo4j を使用しましたが、SQL でも問題なく動作します。

于 2015-06-07T06:23:22.663 に答える
0

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});
});
于 2017-01-28T23:20:40.137 に答える