将行为附加到流星集合的最佳方法是什么?

时间:2013-02-21 16:22:13

标签: backbone.js model meteor behavior

在Meteor中,当您从数据库中检索记录时,它只是一条记录。因此,如果我有一个名为Dogs的集合,dog可能有fur: 'brown'breath: 'stinky',但它没有bark()方法。

显然,我可以创建一些期望dog作为参数的函数,然后对dog执行操作。我甚至可以将所有这些函数封装到一个构造函数中。我对这种方法并不是很疯狂,但是如果某人有一个干净而明智的方法来做到这一点,我就全都听见了。

我的另一个想法是将dog包裹在Backbone.Model中。这可能很有趣,因为fetchsave可以重新定义为findinsertupdate,您也可以在那里定义所有行为,但我已经读到这种事情通常是气馁的。

有没有正确的方法呢?是否有正式的Meteor.Model正在进行中?其他人如何解决这个问题?

修改

对于那些在接受回答后一年内提出此问题的人:在编辑本文时,我使用的是Exygy's minimongoid mrt package,这对haihappen's version有一些改进,这些改进已在博文中提到通过接受的答案。

我目前正在为存储库做贡献,使结果集更像关系。希望其他人可以使用它,并倾向于提供有用的功能。

修改

另一个答案建议在创建集合时使用transform属性。虽然我肯定更喜欢我自己并不需要自己构建的东西,但这个功能增加了很多可能性,我希望任何正在研究ORM for Meteor的团队都会利用这个核心优势

Here's a blog post解释如何使用transform属性。

另外,minimongoid is now available as a Meteor package,我仍在使用它。它支持验证和声明关系。我也为这个软件包添加了一些功能,所以如果一个电路板有很多部分,board.pieces().create(attributes)将保留一条带有piece的新attributes记录,并会自动与board相关联{1}}。在我看过的各种解决方案中,这似乎是最全面的。

6 个答案:

答案 0 :(得分:28)

您可以使用Collection中的transform参数来使用自定义函数

重载对象
var Dogs = new Meteor.Collection("dogs", 
{
    transform:function(entry)
    {
        entry.bark = function(){ console.log(this.barkSound);};
        return entry;
    }
});

然后:

var aDogID = new Dogs.insert({barkSound: "ruff"})
Dogs.find(aDogID).bark(); // "ruff"

加分:如果出于任何原因您想使用Andrew Ferk提出的类似概念,只需使用_.defaults(object,* defaults)函数。

var defaults = {
             barkSound: "ruff",
             bark: function() {
                        console.log(this.barkSound);
                    }
            }

Dogs = new Meteor.Collection("dogs",
        {
            transform: function(object) {
                return _.defaults(object, defaults);
            }
        });

答案 1 :(得分:4)

这是重写Meteor.Collection以支持对象方法的开始。

Meteor.Kollection = Meteor.Collection;
Meteor.Kollection.extend = function(constructor) {
  var parent = this;
  var child = function() {
    Meteor.Kollection.apply(this, arguments);
    constructor.apply(this, arguments);
  };

  _.extend(child, parent);

  function __proto__() { this.constructor = child; };
  __proto__.prototype = parent.prototype;
  child.prototype = new __proto__;

  return child;
};

Meteor.Collection = Meteor.Kollection.extend(function(name, options) {
  if (options && options.defaults) {
    this.defaults = options.defaults;
  }
});

Meteor.Collection.prototype.applyDefaults = function(attrs) {
  return _.defaults(attrs, this.defaults);
};

Meteor.Collection.prototype.create = function(attrs) {
  if (typeof attrs !== "object") attrs = {};
  return this.applyDefaults(attrs);
};

Meteor.Collection.prototype.findOne = function(selector, options) {
  var object = Meteor.Kollection.prototype.findOne.apply(this, arguments);
  return this.applyDefaults(object);
};

您可能会注意到新的集合 .create方法,并且已重写集合 .findOne。我想所有集合。*方法都需要被覆盖,但这是一个开始。

那么你能做些什么?

var Dogs = new Meteor.Collection("dogs", { defaults: {
  barkSound: "ruff",
  bark: function() {
    console.log(this.barkSound);
  }
}});

if (Meteor.isClient) {
  var regularDog = Dogs.create();
  regularDog.bark(); // ruff

  var smallDog = Dogs.create({
    barkSound: "yip"
  });
  smallDog.bark(); // yip

  Dogs.insert(smallDog, function(error, id) {
    Dogs.findOne(id).bark(); // yip
  });
});

我不确定这是怎么发生的,但是插入对象中的任何函数都会被删除。因此,我们可以直接将方法应用于对象。首先,通过传入具有defaults属性的对象来创建集合。此属性可以包含属性或方法。要为给定集合创建新对象,请使用集合 .create(attrs),其中attrs是一个包含附加或重写属性和方法的选项参数。

答案 2 :(得分:4)

Astronomy是对流星模型这个老问题的新答案。作者有许多计划中的功能正在进行中,并得到其他着名的Meteor包作者的支持。唯一的缺点是也许它有点前沿。

天文学也是highly modularized,是建立流星包装/模块化风格的典范。

答案 3 :(得分:3)

虽然可能有official model system in the works,但您现在可以做一些事情:

马里奥·乌勒(Mario Uhler)有一个像coffeescript一样活跃的记录,非常好,https://coderwall.com/p/_q9b1w

Tom Coleman还提供了一个对模型非常有帮助的社区包:https://github.com/tmeasday/meteor-models,您可能需要meteorite将其添加为包。

当然,正如你建议的Backbone。我个人使用js原型,但不是每个人都可能对它们很舒服,我只是使用它们,因此当meteor的模型系统出来时很容易转换,它也很容易在客户端和服务器之间共享,而无需添加太多的包。

答案 4 :(得分:2)

就流星而言,这是一个相对古老的问题,但我认为dburles:collection-helpers符合你想要实现的目标,通过实施Flavien Volken的建议。也许这对最近在这里游荡的人来说很有用。

答案 5 :(得分:0)

除了@Flavien Volken的回答,您可以将参数传递给您添加到集合中的方法。

{{# if is_watched currentUser._id }}
    Watched
{{ else }}
    Not watched
{{/ if }}

在模板中(传递登录用户的id):

{"siteAccountId":12803756,"isCustom":false,"credentialsChangedTime":1442572129,"siteRefreshInfo":{"siteRefreshStatus":{"siteRefreshStatusId":1,"siteRefreshStatus":"REFRESH_TRIGGERED"},"siteRefreshMode":{"refreshModeId":1,"refreshMode":"MFA"},"updateInitTime":1442572129,"nextUpdate":1442573029,"code":801,"suggestedFlow":{"suggestedFlowId":2,"suggestedFlow":"REFRESH"},"noOfRetry":0,"isMFAInputRequired":true,"siteAddStatus":{"siteAddStatusId":13,"siteAddStatus":"ADD_IN_PROGRESS"}},"siteInfo":{"popularity":0,"siteId":16486,"orgId":1148,"defaultDisplayName":"Dag Site SecurityQA","defaultOrgDisplayName":"Demo Bank","enabledContainers":[{"containerName":"bank","assetType":1},{"containerName":"credits","assetType":2}],"baseUrl":"http://64.14.28.129/dag/index.do","loginForms":[],"isHeld":false,"isCustom":false,"mfaType":{"typeId":4,"typeName":"SECURITY_QUESTION"},"siteSearchVisibility":true,"isAlreadyAddedByUser":true,"isOauthEnabled":false,"hdLogoLastModified":0,"isHdLogoAvailable":false},"created":"2015-09-18T03:28:49-0700","retryCount":0,"disabled":false,"isAgentError":false,"isSiteError":false,"isUARError":false}