Backbone.js 什么';将行为附加到流星集合的最佳方式是什么?

Backbone.js 什么';将行为附加到流星集合的最佳方式是什么?,backbone.js,model,meteor,behavior,Backbone.js,Model,Meteor,Behavior,在Meteor中,当您从数据库检索记录时,它只是一条记录。因此,如果我有一个名为Dogs的集合,dog可能有fur:'brown'或breath:'doomy',但它没有bark()方法 显然,我可以创建一些函数,这些函数期望将dog作为参数,然后对该dog执行操作。我甚至可以将所有这些函数封装到一个构造函数中。我并不热衷于这种方法,但如果有人有一种干净而明智的方法来做这件事,我会洗耳恭听 我的另一个想法是把狗包在主干中。这可能很有趣,因为fetch和save可以被重新定义为执行find和ins

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

显然,我可以创建一些函数,这些函数期望将
dog
作为参数,然后对该
dog
执行操作。我甚至可以将所有这些函数封装到一个构造函数中。我并不热衷于这种方法,但如果有人有一种干净而明智的方法来做这件事,我会洗耳恭听

我的另一个想法是把
包在
主干中。这可能很有趣,因为
fetch
save
可以被重新定义为执行
find
insert
update
,您也可以在那里定义您的所有行为,但我已经了解到这类事情通常是不鼓励的

有正确的方法吗?是否有一款流星模型正式投入使用?其他人是如何解决这个问题的

编辑

对于那些在接受答案一年多后提出这个问题的人:在我使用这个编辑时,它有一些改进,这些改进在被接受答案链接的博客文章中提到

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

编辑

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

解释如何使用
转换
属性

还有,我还在用它。它支持验证和声明关系。我还为此包添加了一些功能,因此,如果一块板有许多块,
board.pieces().create(attributes)
将使用给定的
属性保存一条新的
记录,并将自动与
关联。在我见过的各种解决方案中,这似乎是最全面的解决方案。

虽然可能存在问题,但您现在可以做一些事情:

有一个是Mario Uhler写的,很像activerecord,很不错,用咖啡脚本写的:

还有一个由Tom Coleman制作的社区包,它对模型非常有帮助:,您可能需要将其添加为一个包


当然,正如你所建议的。我个人使用js原型,但并不是每个人都喜欢,我只是使用了它们,这样在meteor的模型系统出现时很容易转换,也很容易在客户端和服务器之间共享,而无需添加太多的包。

这是覆盖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是一个选项参数,包括附加的或重写的属性和方法。

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

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

奖励:如果出于任何原因,您希望使用Andrew Ferk提出的类似概念,只需使用u.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);
            }
        });

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

是对流星模型这个老问题的新答案。作者有更多的功能计划,是在工作和其他著名的流星包作者的支持。唯一的缺点可能是它有点流血


天文学也是流星包装/模块化风格建筑的一个主要例子。

除了@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):


谢谢你的回复。如果不太麻烦的话,你能提供一个简单的例子说明如何利用js原型来解决这个问题吗?我会在一段时间内更新这个,我只需要清理一下原型,一个bitI决定使用的Minimongoid,这很符合实际情况:-)我不明白为什么集合的转换参数不够。谢谢@0,很抱歉我没有早点看到这个。我已经用一些关于
transform
的注释更新了OP,这绝对值得一提。值得一提的是软件包。@DanDascalescu,谢谢你的链接!它不太适合我所寻找的,但在其他方面对我非常有用。非常感谢!这看起来是正确的、官方的做法。我要用这个。这是一个很棒的解决方案,谢谢!!!现在完全改变了我的流星代码。我怎么会在文档中漏掉这一点呢???在这个主题上贴上更多的例子:谢谢,我很感激被新技术更新。我仍然在使用minimongoid(),它支持像
has\u one
behings这样的声明
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;
    }
});
{{# if is_watched currentUser._id }}
    Watched
{{ else }}
    Not watched
{{/ if }}