简体   繁体   English

如何在Meteor.js中的服务器端转换功能之后设置mongo投影?

[英]How to setup a mongo projection AFTER a server side transform function in Meteor.js?

I need to limit the number of fields sent to the client from a publish function after applying a transform that requires access to the original doc. 在应用需要访问原始文档的转换后,我需要限制从发布功能发送给客户端的字段数。

I'm basically trying to avoid sending potentially huge arrays down to the client, and run a bunch of checks to return a nice neat object to work with. 我基本上是在尝试避免向客户端发送潜在的巨大数组,并运行一堆检查以返回一个很好的整洁对象以供使用。

Heres the function I've got now - it works, just the not the way I'd like, basically limiting the fields given to observe function. 这是我现在拥有的功能-它可以正常工作,但并不是我想要的那样,基本上限制了要观察功能的字段。 is there a way to add the projection after the observe / transform. 有没有办法在观察/变换之后添加投影。

Meteor.publish('network', function() {

  var self = this;

  // get the user values initially
  var user = Meteor.users.findOne(self.userId);
  var followingUsers = user.following ? user.following.users || [] : [];
  var followingChannels = user.following ? user.following.channels || [] : [];

  var transformMedia = function(doc) {
    // get the user each time to keep this publication reactive
    votesUp = doc.votes ? doc.votes.up || [] : [];
    votesDown = doc.votes ? doc.votes.down || [] : [];
    favourites = doc.votes ? doc.votes.favourites || [] : [];

    doc.userActions = {
      votedUp: _.contains(votesUp, doc._id) ? 1 : 0,
      votedDown: _.contains(votesDown, doc._id) ? 1 : 0,
      isFavourite: _.contains(favourites, doc._id) ? 1 : 0,
      played: _.contains(doc.played, self.userId) ? 1 : 0,
    };

    return doc;
  };

  var networkQuery = Media.find({
    $and: [
    {
        $and: [
          {processedAt: { $exists: true} },
          {processedStatus: 'successful'},
          {publishStatus: 'published'}
        ]
      },
      {
        // if created by this user, user they follow or channels they subscribe to
        $or: [
          {createdBy: self.userId },
          {createdBy: { $in: followingUsers} },
          {channels: { $in: followingChannels} },
        ]
      }

      // TODO : add not banned or trashed once implemented
    ]
  }, mediaModifiers).observe({
    added: function(doc) {
      self.added('media', doc._id, transformMedia(doc));
    },
    changed: function(doc, oldDoc) {
      self.changed('media', doc._id, transformMedia(doc));
    },
    removed: function(doc) {
      self.removed('media', doc._id, transformMedia(doc));
    },
  });

  self.onStop(function() {
    networkQuery.stop();
  });

  self.ready();

});

I had a similar issue once . 我曾经有过类似的问题 I dealt with it using cursor.observe() + a custom function (as you did) and I just added a _.pick() to filter the unnecessary fields. 我使用cursor.observe() +一个自定义函数来处理它(就像您所做的那样),我只是添加了一个_.pick()来过滤不必要的字段。 Have a look at this publication code for an example (the white list docToPublish part especially): 请看下面的发布代码示例(尤其是白名单docToPublish部分):

var self = this;

// Modify the document we are sending to the client.
function filter(doc) {
  var length = doc.item.length;

  // White list the fields you want to publish.
  var docToPublish = _.pick(doc, [
      'someOtherField'
  ]);

  // Add your custom fields.
  docToPublish.itemLength = length;

  return docToPublish;                        
}

var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
            // Use observe since it gives us the the old and new document when something is changing. 
            // If this becomes a performance issue then consider using observeChanges, 
            // but its usually a lot simpler to use observe in cases like this.
            .observe({
                added: function(doc) {
                    self.added("myCollection", doc._id, filter(doc));
                },
                changed: function(newDocument, oldDocument)
                    // When the item count is changing, send update to client.
                    if (newDocument.item.length !== oldDocument.item.length)
                        self.changed("myCollection", newDocument._id, filter(newDocument));
                },
                removed: function(doc) {
                    self.removed("myCollection", doc._id);                    
                });

self.ready();

self.onStop(function () {
  handle.stop();
});

This code is borrowed from @datacarl answer to my topic mentioned above. 这段代码是从@datacarl答案借来的,上面提到了我的主题。

Note that if you scale up to several servers, the cons of this approach is that each server will have to run the cursor.observe() function. 请注意,如果您最多可以扩展到多个服务器,则此方法的缺点是每个服务器都必须运行cursor.observe()函数。

You also forgot to make your publication ready and dispose of your observers at the end of your publication (it might be because you didn't paste all the pub). 您还忘记准备发布,并在发布结束时将观察员丢弃(这可能是因为您没有粘贴所有发布)。 It would look like this : 它看起来像这样:

self.ready();
self.onStop(function () {
  networkQuery.stop();
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM