Is adding helpers to collections a bad idea?

I’m currently doing this and it works fine, but is it a bad idea?

AAA = new Mongo.Collection('aaa');

AAA.helpers = {
  getOptions: function() {
    return function() {
      var lang = Session.get('currLang');
      return AAA.find().map(function(el) { 
        return { id: el._id, name: el.name[lang.code] }
      });
    }
  }
};

I use AAA.helpers.getOptions() inside helpers in the client side to populate dropdown inputs.

One source of trouble would be if Mongo.Collection receives official support for helpers in the future. Is there a better way to do this? I don’t want to use global helpers for this, because all global helpers end up in the same space. The idea of “global” sounds like a source of trouble in a non trivial program. getOptions is a method related only to a specific collection, so to me it makes sense to attach it to the collection. What are your thoughts on this?

1 Like

This looks good to me. To go deeper, you can have a look at:

1 Like

Thanks, I tried collection-helpers, but I noticed it works at document-level, not at collection-level. In this case it meant calling Session.get(‘currLang’) for each item in the collection, which I think is less efficient.

That’s why I decided to try this approach.

I have seen this used in other places, and I am doing it too in one of my projects.
Seems to work really well.

1 Like

I second the idea of collection helpers, I think it is a great way to DRY up your code without a lot of crazy overhead to maintain.

That being said, I would make sure you aren’t writing collection helpers that are outputting html content, just output things you might put into a template or use in more than one spot in a template helper, template, or from another collection helper call.

are you doing this for the purpose of returning strings for a multi-lingual site? Have you looked at the messageFormat package for Meteor? That is what we use. We find it to be very elegant, powerful and flexible.

http://messageformat.meteor.com/

Other people have already given you helpful feedback,
so I’ll suggest a package for supporting i18n direclty in collections:

Thanks, that was the idea, to avoid repeating the same helpers in multiple places. And yes, I only return data, no html.

We’re already using TAPi18n and T9n (the second one required by useraccounts:core). Maybe in the next project :slight_smile:

@chenroth I took a look at tap-i18n-db at the beginning of the project, but it was not obvious to me what the advantages of using it are. It implies making many changes to the database structure, queries, and more. Maybe a week of work at this stage.

it has a decent i18n storage pattern (dictionary in db document where language is key), it saves you the logic pattern of extracting just the required translation and it’s reactive

Indeed, I’ve had the luxury to integrate it in a current project still in development stage :smile:

A side note:

It’s good advice to add an app specific prefix to all the names that your app puts in a shared or global scope – basic namespacing prevents your more unimaginatively named variables from unwittingly bulldozing an identically named variable from a package.

(If you didn’t run into any collisions yet, it’s likely only a matter of minutes – as the code base grows, the birthday paradox comes into play :wink:).

Using a somewhat unique, app-wide prefix is a best practice that clearly also applies to new properties on foreign objects or instances, since 1) the risk of collision in the future becomes negligible, and 2) it will be obvious, in relation to maintenance, where the property is coming from.

The naming scheme that I’m using around template names, CSS classes, route names, global collection handles, etc. in the fairly large project that I’m working on, looks something like this:

<app><Module><Feature> (camelCase)
<app>-<module>-<feature> (train case)

not sure if I understand this 100%, but shouldn’t you be limited the data in this collection more? Assuming the session var “currLang” is a user-interface setting, shouldn’t you apply this constraint in your subscription query instead, so that your collection only has the data you need i.e. only data relevant to the current language? It’s especially important for mobile performance that you are very intelligent in only returning the minimal data needed.

If you explain a bit more about the role of this collection in your app I could offer more concrete advice.

I’m surprised you have to lookup and extract the strings yourself if you are using an internalization package. Doesn’t tapi18n provide built-in helpers?

Thanks for all the suggestions. I had not thought about publishing only specific languages. In any case the amount of data is very small, and often the data is shown in multiple languages (to translate the content).

If I would start today I might use tap-i18n-db, or evaluate if structuring the data as { en: {a:1, b:2}, es: {a:3, b:4}} instead of {a: {en:1, es:2}, b: {en:3, es:4}} might make things easier.