22

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

显然,我可以创建一些期望 adog作为参数的函数,然后对它执行操作dog。我什至可以将所有这些函数封装到一个构造函数中。我对这种方法并不疯狂,但如果有人有一种干净而明智的方法来做到这一点,我会全力以赴。

我的另一个想法是dogBackbone.Model. 这可能很有趣,因为fetchandsave可以被重新定义为做findand insertor update,你也可以在那里定义你的所有行为,但我读过这种类型的事情通常是不鼓励的。

有正确的方法吗?有没有Meteor.Model正式的作品?其他人是如何解决这个问题的?

编辑

对于那些在接受答案一年多后提出这个问题的人:在此编辑时,我正在使用Exygy 的 minimongoid mrt 包,它对接受答案链接的博客文章中提到的haihappen 版本进行了一些改进。

我目前正在为存储库做出贡献,以使结果集更像关系。希望其他人能利用它并愿意贡献有用的功能。

编辑

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

这是一篇解释如何使用该transform属性的博客文章。

此外,minimongoid 现在可以作为 Meteor 包使用,我仍在使用它。它支持验证和声明关系。我也为这个包添加了一些功能,所以如果一个板有很多块,board.pieces().create(attributes)将保留一个新piece记录attributes并自动与board. 在我见过的各种解决方案中,这似乎是最全面的。

4

6 回答 6

28

您可以使用transformCollection 中的参数使用自定义函数重载对象

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);
            }
        });
于 2014-02-04T07:39:49.950 回答
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);
};

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

那么你能用这个做什么呢?

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属性的对象来创建您的集合。该属性可以包括属性或方法。要为给定集合创建新对象,请使用collection .create(attrs),其中 attrs 是一个选项参数,其中包括附加或覆盖的属性和方法。

于 2013-02-21T21:56:06.117 回答
4

天文学是对流星模型这个老问题的新答案。作者计划了更多功能正在开发中,并得到其他著名 Meteor 包作者的支持。唯一的缺点可能是它有点流血。

天文学也是高度模块化的,这是以流星打包/模块化风格构建的主要示例。

于 2015-08-20T01:53:58.950 回答
3

虽然可能有一个官方模型系统正在开发中,但您现在可以做一些事情:

马里奥·乌勒(Mario Uhler)有一个像 activerecord 一样非常好,在咖啡脚本中:https ://coderwall.com/p/_q9b1w

还有一个由 Tom Coleman 制作的社区包,它对模型非常有用:https ://github.com/tmeasday/meteor-models ,您可能需要陨石将其添加为一个包。

当然,正如您建议的 Backbone。我个人使用js原型,但可能不是每个人都喜欢,我只是使用它们,所以当meteor的模型系统出来时它很容易过渡,也很容易在客户端和服务器之间共享,不需要添加太多的包。

于 2013-02-21T16:52:17.847 回答
2

就 Meteor 而言,这是一个相对古老的问题,但我认为dburles:collection-helpers通过实施 Flavien Volken 的建议符合您想要实现的目标。也许它对最近在这里闲逛的人有用。

于 2015-04-02T17:04:20.590 回答
0

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

Car = new Mongo.Collection('car', {
    transform: function(entry) {
        entry.is_watched = function(userId) {
            var is_watched = false;
            if (entry.watchList) {
                for (var i in entry.watchList) {
                    if (entry.watchList[i].userId == userId) {
                        is_watched = true;
                        break;
                    }
                }
            }
            return is_watched;
        };
        return entry;
    }
});

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

{{# if is_watched currentUser._id }}
    Watched
{{ else }}
    Not watched
{{/ if }}
于 2015-09-21T05:44:47.887 回答