【问题标题】:Coffeescript class find or create mongo documentCoffeescript 类查找或创建 mongo 文档
【发布时间】:2013-08-28 10:27:27
【问题描述】:

我正在尝试编写一个咖啡脚本类,当从它构造一个新对象时,它会检查是否传递了一个 ID。如果是这样,请尝试查找匹配的文档并从中填充对象。如果没有传递 ID,则生成一个新 ID 并创建一个新文档。我正在使用 mongojs 连接到我的 mongodb。但是,当我从 TestObject 类创建一个新对象时,它会引发一个错误,即集合名称需要是一个字符串。我将@collection 设置为该类上的字符串,因此我控制台记录了@collection 属性及其未定义。这是怎么回事,我怎样才能使它工作?

class MongoObject
    @collection
    constructor: (id) ->
        @_id = if typeof id is 'undefined' then require('node-uuid').v4() else id
        @db = require('mongojs') config.mongo_server, [@collection]

        @db[@collection].findOne
            _id: @_id,
            (error, story) ->
                # Matching document found. Import data from document
                if not error and story
                    for field, value of story
                        @[field] = value if field is not '_id'

                # Matching document not found. Creating new one
                if not error and not story
                    @db[@collection].save
                        id: @id

                # Error occured
                if error and not story
                    console.error error

                return

class TestObject extends MongoObject
    @collection = 'TestObjects'
    constructor: (id) ->
        super('TestObject')

编辑

重新阅读我的代码,很明显这是构造函数和 @collection 在 MongoObject 中未定义的问题。有没有更好的方法来做到这一点?我可以创建一个 setupDB 方法并在每个类的构造函数中调用它,该构造函数在超级调用之后扩展 MongoObject 但不是我所希望的。

编辑 2

我修改了我的代码。但是,我现在收到 constructor 未定义的错误。当我查看编译后的 javascript 时,它指向 MongoObject 代码顶部的 constructor;。奇怪的是,coffeescript 没有输入var constructor;,这通常会发生。我已经发布了翻译后的 javascript 仅供参考

咖啡脚本

class MongoObject
    collection: undefined
    constructor: (id) ->
        @_id = if typeof id is 'undefined' then require('node-uuid').v4() else id
        @db = require('mongojs') config.mongo_server, [@collection]

        @db[@collection].findOne
            _id: @_id,
            (error, story) ->
                # Matching document found. Import data from document
                if not error and story
                    for field, value of story
                        @[field] = value if field is not '_id'

                # Matching document not found. Creating new one
                if not error and not story
                    @db[@collection].save
                        id: @id

                # Error occured
                if error and not story
                    console.error error

                return

class TestObject extends MongoObject
    collection = 'TestObjects'
    constructor: (id) ->
        super('TestObject')

Javascript

MongoObject = (function() {
  MongoObject.prototype.collection = void 0;

  function MongoObject(id) {
    this._id = typeof id === 'undefined' ? require('node-uuid').v4() : id;
    this.db = require('mongojs')(config.mongo_server, [this.collection]);
    this.db[this.collection].findOne({
      _id: this._id
    }, function(error, story) {
      var field, value;
      if (!error && story) {
        for (field in story) {
          value = story[field];
          if (field === !'_id') {
            this[field] = value;
          }
        }
      }
      if (!error && !story) {
        this.db[this.collection].save({
          id: this.id
        });
      }
      if (error && !story) {
        console.error(error);
      }
    });
  }

  return MongoObject;

})();

TestObject = (function(_super) {
  var collection;

  __extends(TestObject, _super);

  collection = 'TestObjects';

  function TestObject(id) {
    TestObject.__super__.constructor.call(this, 'TestObject');
  }

  return TestObject;

})(MongoObject);

编辑 3

根据我的 cmets 更新了我的代码。它说@constructor.collection

中是未定义的
@db[@constructor.collection].save
    id: @id

我假设它是因为它在保存的回调函数中。前进一步,后退两步。

修改后的代码

class MongoObject
    @collection
    constructor: (id) ->
        @_id = if typeof id is 'undefined' then require('node-uuid').v4() else id
        @db = require('mongojs') config.mongo_server, [@constructor.collection]

        @db[@constructor.collection].findOne
            _id: @_id,
            (error, story) ->
                # Matching document found. Import data from document
                if not error and story
                    for field, value of story
                        @[field] = value if field is not '_id'

                # Matching document not found. Creating new one
                if not error and not story
                    @db[@constructor.collection].save
                        id: @id

                # Error occured
                if error and not story
                    console.error error

                return

class TestObject extends MongoObject
    @collection: 'TestObjects'
    constructor: (id) ->
        super('TestObject')

【问题讨论】:

  • 您希望collection = 'TestObjects' 做什么以及为什么要在构造函数中使用super('TestObjects')
  • super 被调用以运行其父类的构造函数。 super 在 python 中的使用方式相同。 arcturo.github.io/library/coffeescript/03_classes.html “在实践中,这与在 Ruby 或 Python 中调用 super 的效果完全相同,调用重写的继承函数。”我想先调用父构造函数逻辑
  • 最终,我想要一个基类,其中包含 db 连接代码,并且每个扩展类都定义其集合名称,因此@db 将为每个类定义指向正确的集合。所以我不会一次又一次地重复代码。
  • 我知道super 是做什么的,但你为什么用字符串调用它,为什么你说collection = ... 而不是collection: ...p = ...p: ... 的意思完全不同。如果你 collection 是一个类属性,那么说 @collection: ... 并在实例方法中将其引用为 @constructor.collection
  • 嗯,基本结构有效 (jsfiddle.net/ambiguous/PTLVN),也许 findOne 使用的 @ 与您预期的不同,也许您应该使用 => 来定义该回调。

标签: javascript mongodb coffeescript mongojs


【解决方案1】:

我认为您对 @ 在班级级别的含义感到困惑。一个简化的示例应该会有所帮助,这个 CoffeeScript:

class B
    @p: 'b'

和这个 JavaScript 一样:

var B = (function() {
  function B() {}
  B.p = 'b';
  return B;
})();

因此您可以看到p 是一个直接附加到C 类/函数的类属性。但是当您在一个方法中时,例如constructor@ 指的是实例,所以在您的情况下,@collection 将是undefined,因为您将collection 定义为一个类属性。

您可能希望 collection 成为实例属性:

class MongoObject
    collection: undefined
    constructor: (id) ->
        # @collection is what you expect it to be in here

class TextObject extends MongoObject
    collection: 'TextObject'

演示:http://jsfiddle.net/ambiguous/TzK5E/

或者,您可以将collection 保留为类属性并通过@constructor 引用它:

class MongoObject
    @collection: undefined
    constructor: (id) ->
        # @constructor.collection is what you expect it to be in here

class TextObject extends MongoObject
    @collection: 'TextObject'

演示:http://jsfiddle.net/ambiguous/wLjz3/

【讨论】:

  • 这绝对有效。我真的认为这将是一个类变量,因为它为类和从它创建的任何对象设置。实例变量 我认为从类创建的对象的变量是彼此唯一的。不过学习新东西还是不错的。
  • 它是一个类变量,但您必须在实例方法中将“类”引用为@constructor
【解决方案2】:

我相信您会希望使用稍微不同的语法来引用 collection 名称:

class MongoObject
    @collection 
    constructor: (id) ->
       alert @constructor.collection


class TestObject extends MongoObject
    @collection = 'TestObjects'
    constructor: (id) ->
        super('TestObject')

t = new TestObject

提醒"TestObjects"

关键是@constructor.collection的使用。

【讨论】:

    【解决方案3】:

    这是我最终得到的解决方案

    class MongoObject
        @collection
        constructor: (id) ->
            @_id = if typeof id is 'undefined' then require('node-uuid').v4() else id
            @db = require('mongojs') config.mongo_server, [@constructor.collection]
    
            @db[@constructor.collection].findOne
                _id: @_id,
                (error, doc) =>
                    # Matching document found. Import data from document
                    if not error and doc
                        console.log 'Document found. Updating.'
                        for field, value of doc
                            @[field] = value if field is not '_id'
    
                    # Matching document not found. Creating new one
                    if not error and not doc
                        console.log 'No document found. Creating.'
                        @db[@constructor.collection].save
                            _id: @_id
    
                    # Error occured
                    if error and not doc
                        console.error error
    
                    return
    
    class TestObject extends MongoObject
        @collection: 'TestObjects'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多