Javascript 如何在集合中仅查找具有一组ID的最新文档
我有一个集合Javascript 如何在集合中仅查找具有一组ID的最新文档,javascript,mongodb,meteor,mongodb-query,Javascript,Mongodb,Meteor,Mongodb Query,我有一个集合Feeds和一个集合FeedElementsFeedElements文档通过feedId字段引用Feeds集合。此外,所有FeedElements文档都有日期字段submitted 我只想发布最新的(由字段submitted确定)FeedElements文档,该文档恰好对应于一个Feeds文档 以下是我尝试过的: Meteor.publish('recentFeedElements', function (userId) { var feedIds = Feeds.find(
Feeds
和一个集合FeedElements
FeedElements
文档通过feedId
字段引用Feeds
集合。此外,所有FeedElements
文档都有日期字段submitted
我只想发布最新的(由字段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()中使用limit
和sort
组合,我只会得到所有Feed
文档中的最新文档。然而,我希望有一个严格的1-1关系。因此,一个Feed
document->最新的FeedElements
文档,并带有适当的引用。您可以通过聚合框架,&>获得该文档
如果我没弄错的话,您希望每个提要都有lastActivity
字段,其中包含此提要最后提交的提要元素的时间戳。您希望此字段是被动的,并且不希望发布所有提要元素
在这种情况下,聚合不是解决方案,因为Meteor不允许反应聚合
您需要使用低级发布API:(参见示例部分)
低级发布API(this.added
/this.removed
/this.changed
/others)允许您完全控制通过Meteor.publish方法向客户端发送的数据
以下是解决问题的方法(我使用ES2015语法):
//client/client.js
subscribe('userFeeds',{userId:1});
我还准备了github回购协议。只需git clone
和meteor run
就可以分享模型了吗?如果我理解你的意图,那么你想要的是每个提供的“feedId”值的“最新”文档,如果它当然存在,对吗?这里您应该猜到的一个明显的情况是,最好为每个“feedId”提交单独的查询,然后将结果合并到单个响应中。相关:谢谢你的帮助!是的,这正是我想要的。这里是每个查询和组合的“并行”处理的更好示例:。这两个问题非常相似,在“top n”的意义上与您自己的要求相似。他们都说运行单独的查询是最好的选择,后者有一个编码的例子可以遵循。在您的服务器端方法中建立此文件,并可以选择发布。@BlakesSeven感谢您的帮助。我读了这两篇文章,但我很难通过$in
对元素进行分组。你能给我一个提示吗?谢谢你的帮助!很不幸,这不符合我的要求。通过聚合,我得到以下结果:[{feedId:“123”,firstFeedElement:Object}]
。但是,我希望得到以下结果:[Object,Object,Object,…]
。数组中的对象表示每个提供的feedId
值的最新文档。例如,如果我有10个feedId
s,我希望有一个包含10个FeedElements
的数组,这些元素是与一个feedId
对应的最新文档(如果该文档存在)。@user3475602:您希望10个feedId中的每一个都有10个feedElementObjects吗?(表示100个feedElement对象,每个10个)我有两个集合:Feeds
和FeedElements
。每个FeedElements
文档都通过feedId
引用一个Feeds
文档。现在,我只希望每个feedId
有一个(最新的)FeedElements
文档(正好对应一个Feeds
文档)。因此,结果数组中的所有对象都是FeedElements
文档,每个元素都引用一个Feeds
文档,并且是最新的一个,因为可能有多个FeedElements
文档通过feedId
引用相同的Feeds
文档。因此,10个不同的feedId
s,10个不同的feedelement
文档(最新)。@user3475602:我相信你一定得到了这样的结果:[{feedId:“1”,firstFeedElement:Object},{feedId:“2”,firstFeedElement:Object},{feedId:“3”,firstFeedElement:Object}…]。您将获得每个feedId的文档行。您需要在$match部分通过10个feed的feedId。谢谢您的建议!但是,我不想设置另一个字段。我认为聚合是一种方式。我尝试了@Somnath Muluk的建议,但不幸的是他给了我一个错误的管道。当使用包和时,Meteor中的Reavtive聚合确实有效。不过,谢谢你的努力!
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
}
}
]
)
// 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();
}
});
});