Meteor-Community-Packages / meteor-collection-hooks

Meteor Collection Hooks
https://atmospherejs.com/matb33/collection-hooks
MIT License
657 stars 92 forks source link

Example of after.find where the documents are modified #211

Closed rws-github closed 7 years ago

rws-github commented 7 years ago

I need to manipulate documents returned by find, but its unclear to me how I can given a cursor. Can this be done with collection hooks or do I have to instead observe in the publish instead?

namirsab commented 7 years ago

it depends on what you want to do. If you want to change the documents always after fetching them, maybe what you need is a transform in the collection, and not an after.find hook :smile:

rws-github commented 7 years ago

I'm specifically trying to encrypt/decrypt values on the user record so its encrypted during storage. I just tried using transform which seemed to be getting called, but I was still getting encrypted values on the client using:

  const usersFind = Meteor.users.find
  const usersFindOne = Meteor.users.findOne

  Meteor.users.find = function (selector, options) {
    selector = selector || {}
    options = options || {}
    return usersFind.call(this, selector, _.extend({transform: decryptUserDoc}, options))
  }

  Meteor.users.findOne = function (selector, options) {
    selector = selector || {}
    options = options || {}
    return usersFindOne.call(this, selector, _.extend({transform: decryptUserDoc}, options))
  }

If I change the internals of accounts_server.js to this, it seems to work:

  accounts._server.publish(null, function () {
    if (this.userId) {
      const cursor = accounts.users.find({
        _id: this.userId
      }, {
        fields: {
          profile: 1,
          username: 1,
          emails: 1
        }
      })
      .observe({
        added: (doc) => {
          this.added('users', doc._id, Encryption.decryptUserDoc(doc))
        },
        changed: (doc) => {
          this.changed('users', doc._id, Encryption.decryptUserDoc(doc))
        }
      });
      this.ready()
      this.onStop(() => { cursor.stop() })
    } else {
      return null;
    }
  }, /*suppress autopublish warning*/{is_auto: true});
rws-github commented 7 years ago

This does not work either:

Meteor.users.before.find(function (userId, selector, options) {
    options.transform = decryptUserDoc
  })
namirsab commented 7 years ago

This is what i'm doing, and it works. But it's undocumented. Maybe there is a better way to do it:

Meteor.users._transform = function (document) {
    // Decrypt here
    const decryptedDocument = decrypt(document);
    return decryptedDocument;
}
rws-github commented 7 years ago

That does not appear to work for me. If I log Meteor.user() on the client, I still see encrypted values.

I am putting your example in a Meteor.isServer because the bits of the encryption can't be on the client.

I have a solution, so I will close this.

Thanks for all the responses.