2015-11-08 4 views
14

私は、コレクションFeedsとコレクションFeedElementsを持っています。 FeedElements文書はfeedIdフィールドを介してFeedsコレクションへの参照を持っています。さらに、すべてのFeedElements文書に日付フィールドsubmittedがあります。IDの集合で最新の文書を見つける方法

最新の(フィールドsubmittedで)FeedElementsというドキュメントのみを公開したいのですが、それはちょうどFeedsというドキュメントに対応しています。

Meteor.publish('recentFeedElements', function (userId) { 
    var feedIds = Feeds.find({'userId': userId}).map(function(feed) { 
     return feed._id; 
    }); 
    if (feedsIds.length > 0) return FeedElements.find({feedId: {$in: feedIds}}, {sort: {submitted: -1}); 
    else this.ready(); 
}); 

問題は、私はFeedElements.find()クエリ内sortと組み合わせてlimitを使用している場合、私はすべてのFeedの文書の最新のドキュメントを取得するには、次のとおりです。ここで

は、私がしようとしているものです。しかし、私は厳密な1対1の関係を持ちたいと思う。だから、Feed文書 - >最新のFeedElements文書と適切な参照。

+0

モデルを共有できますか? –

+0

私があなたの意図を理解しているなら、あなたが望むのは、もちろん存在するならば、それぞれの "feedId"値の "最新の"ドキュメントでしょうか?ここで推測しておくべき明確なケースは、それぞれの「フィードID」に対して別々のクエリを提出し、その結果を単一のレスポンスに結合する方が良いということです。関連:[mongodb集約で各グループを制限してソートする](http://stackoverflow.com/questions/33458107/limit-and-sort-each-group-by-in-mongodb-using-aggregation/33458267#33458267) –

+0

ご協力いただきありがとうございます!はい、まさに私が欲しいものです。 – user3475602

答えて

0

集計フレームワークによってこれを得ることができます。これは、,$group & $firstです。

db.FeedElements.aggregate(
[ 
    { $match: { feedId: {$in:[1,2,3]}} }, 
    { $sort: { submitted: -1} }, 
    { 
    $group: 
    { 
     _id: "$feedId", 
     firstFeedElement: {$first : "$$ROOT"} // Get first whole document or you can take fields you want 
    } 
    } 
    ] 
) 
+0

ご協力いただきありがとうございます!不幸にも、これは私の要件を満たしていません。あなたの集計では、私は次の結果を得ます: '[{{feedId:" 123 "、firstFeedElement:Object}]'。しかし、私はこの結果を望んでいます: '[Object、Object、Object、...]'。配列内のオブジェクトは、それぞれの 'feedId'値の最新のドキュメントを表します。例えば、私が10個の 'feedId'を持っている場合、10個の' FeedElements'を持つ配列を持っています。これは1つの 'feedId'に対応する最新のドキュメントです(ドキュメントが存在する場合)。 – user3475602

+0

@ user3475602:10個のfeedIdごとに10個のfeedElementObjectが必要ですか? (100個のfeedElementオブジェクトを意味する、それぞれ10個) –

+0

私は2つのコレクションを持っています: 'Feeds'と' FeedElements'。すべての 'FeedElements'文書は' feedId'を介して一つの 'Feeds'文書への参照を持っています。今、 'feedId'(最新のFeedsドキュメントに相当)に1つ(最新)の' FeedElements'ドキュメントしかありません。したがって、結果配列のすべてのオブジェクトは 'FeedElements'ドキュメントであり、各要素は正確に1つの' Feeds'ドキュメントを参照し、最新のものです。複数の 'FeedElements'ドキュメントが存在する可能性があります。 'ドキュメント。したがって、10種類の 'feedId'、10種類の' FeedElements'文書(最新)。 – user3475602

4

私はあなたが右理解していれば、あなたはすべてのフィードがこのフィードの最後の提出給電素子のタイムスタンプが含まれているlastActivityフィールドを持っていると思います。このフィールドを反応させ、すべてのフィード要素を公開しないようにします。

この場合、Meteorはリアクティブな集計を許可しないため、集計は解決策ではありません。

低レベルの公開API:http://docs.meteor.com/#/full/meteor_publish(例のセクションを参照)を使用する必要があります。

低レベルのAPIを公開(this.added/this.removed/this.changed /その他)あなたがMeteor.publishメソッドを介してクライアントに送るどのようなデータを完全に制御できます。ここで

は(私はES2015の構文を使用します)あなたはあなたの問題を解決することができる方法です。


// client/client.js 
Meteor.subscribe('userFeeds', { userId: 1 }); 

// lib/lib.js 
Feeds = new Mongo.Collection('feeds'); 
FeedElements = new Mongo.Collection('FeedElements'); 

// server/server.js 

// When setting `submitted` field, automatically set `submittedAt` field 
// (I use matb33:collection-hooks here) 
FeedElements.before.update((userId, elem, fieldNames, modifier) => { 
    if (modifier.$set.submitted) { 
    modifier.$set.submittedAt = new Date(); 
    } 
}); 

function getLastActivity(feedId) { 
    const lastSubmittedElem = FeedElements.findOne(
    { 
     feedId, 
     submitted: true, 
    }, 
    { 
     sort: { submittedAt: -1 } 
    } 
); 

    return lastSubmittedElem ? lastSubmittedElem.submittedAt : null; 
} 

Meteor.publish('userFeeds', function({ userId }) { 
    const elemsObservers = {}; 

    // Observe all user feeds 
    var feedObserver = Feeds.find({ userId: userId }).observeChanges({ 
    added: (feedId, fields) => { 
     // Observe feed elements of the feed 
     elemsObservers[feedId] = FeedElements.find({ feedId }).observeChanges({ 
     changed: (elemId, fields) => { 
      // Update `lastActivity` field when new element is submitted 
      if (fields.submitted) { 
      this.changed('feeds', feedId, { lastActivity: fields.submittedAt }); 
      } 
     }, 
     }); 

     fields.lastActivity = getLastActivity(feedId); 

     this.added('feeds', feedId, fields); 
    }, 

    changed: (feedId, fields) => { 
     this.changed('feeds', feedId, fields); 
    }, 

    removed: (feedId) => { 
     elemsObservers[feedId].stop(); 
     delete elemsObservers[feedId]; 

     this.removed('feeds', feedId); 
    }, 
    }); 

    this.ready(); 

    this.onStop(function() { 
    feedObserver.stop(); 

    for (const feedId in elemsObservers) { 
     elemsObservers[feedId].stop(); 
    } 
    }); 
}); 

また、私はgithubのレポを準備しました。ちょうどgit cloneおよびmeteor run

+0

あなたの提案をありがとう!しかし、私は別のフィールドを設定したくありません。私は集約が行く方法だと思う。私は@ Somnath Mulukの提案でそれを試しましたが、残念ながら彼は私に間違ったパイプラインを与えました。 Meteorの積極的な集約は、パッケージ[meteor-aggregate](https://github.com/meteorhacks/meteor-aggregate)と[ndevrの回避策](https://github.com/meteorhacks/meteor-aggregate/issues/8)。それにもかかわらず、あなたの努力に感謝します! – user3475602

関連する問題