meteorsimple-schemameteor-collection-hooks

Meteor: how to automatically populate field with length of array stored in other field in a collection?


I have a collection defined with SimpleSchema/Collection2 like this:

Schema.Stuff = new SimpleSchema({
    pieces: {
        type: [Boolean],
    },
    num_pieces: {
        type: Number,
    },

How can I get num_pieces to automatically be populated with the length of the pieces array whenever there is a change?

I am open to using SimpleSchema's autoValue or matb33:collection-hooks. pieces could potentially be changed with quite a few operators, such as $push, $pull, $set, and probably more that Mongo has to offer, and I had no idea how to cope with these possibilities. Ideally one would just look at the value of pieces after the update, but how can you do that and make a change without going into a bit of an infinite loop on the collection-hook?


Solution

  • Here's an example of how you'd do a collection hook 'after update' that prevents the infinite loop:

    Stuff.after.update(function (userId, doc, fieldNames, modifier, options) {
      if( (!this.previous.pieces && doc.pieces) || (this.previous.pieces.length !== doc.pieces.length ) {
        // Two cases to be in here:
        // 1. We didn't have pieces before, but we do now.
        // 2. We had pieces previous and now, but the values are different.
        Stuff.update({ _id: doc._id }, { $set: { num_pieces: doc.pieces.length } });
      }
    });
    

    Note that this.previous gives you access to the previous document, and doc is the current document. This should give you enough to finish the rest of the cases.