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