2013-07-11 138 views
4

在我的應用程序中,我在另一個(另一個實例class A包含一個具有class B實例作爲其屬性之一的對象的數組)中組成了一個coffeescript類。然後我發現了cmather's video about EJSON,並認爲將它與我的物體一起使用會很酷。但是,Meteor似乎並未正確處理其他EJSON對象內部的EJSON對象 - class A可以保存到數據存儲中,並在查詢時返回爲class A,但class B最終會從該集合返回,作爲Object而不是class B實例。當我運行一些測試代碼時,嵌入式EJSON對象似乎首先工作(在初始collection.insert()之後),但是在刷新瀏覽器之後,它返回了簡單的Object或者結構錯誤的對象。我的理論是,minimongo和服務器端mongo的行爲有一些不匹配,但可能還有其他原因。我可以在另一個EJSON對象中嵌入一個EJSON對象嗎?

那麼,有沒有辦法將一個EJSON對象嵌入另一個?也許我的代碼存在缺陷?這只是一個壞主意嗎?我可以讓class A在其constructor中實例化class B項目本身,但似乎EJSON應該能夠處理這個問題。如果您認爲這是一個錯誤,我會很樂意在github上提交問題,但是我認爲我會先在這裏檢查。

如果您需要的代碼嘗試了這一點,你可以試試下面的代碼,其中設置了兩個基本相同的類,一個叫Inner,和一個叫Outer,並創建一個包含一個實例調用outerOuter實例作爲財產innerHereInner。在控制檯中輸入testCollection.insert({outerHere: outer}。現在,testCollection.findOne()可能會爲您提供一個對象,其中對象的innerHere屬性是Inner的正確實例,但如果刷新瀏覽器,則相同的命令可能會返回不同的內容。

如果這個問題很難遵循,讓我知道,我會盡力澄清。

的代碼來設置它(只是做一個新項目的根.coffee文件):

@testCollection = new Meteor.Collection("test") 

class @Outer 
    constructor: (value) -> 
    @value = value 
    clone: -> 
    new Outer(@value) 
    equals: (other) -> 
    _.isEqual(@, other) 
    typeName: -> 
    "Outer" 
    toJSONValue: -> 
    value: @value 


EJSON.addType("Outer", (value)-> 
    new Outer(value) 
) 

class @Inner 
    constructor: (value) -> 
    @value = value 
    clone: -> 
    new Inner(@value) 
    equals: (other) -> 
    _.isEqual(@, other) 
    typeName: -> 
    "Inner" 
    toJSONValue: -> 
    value: @value 


EJSON.addType("Inner", (value)-> 
    new Inner(value) 
) 

@outer = new Outer({innerHere: new Inner ("inner value")}) 
+0

我已經發布了一個拉請求,以大大簡化這件事情的時間:https://github.com/meteor/meteor/pull/1734 –

回答

4

當EJSON調用你的外型toJSONValue,它不會遞歸到結果自動檢測內在類型。同樣,在fromJSONValue(傳遞給EJSON.addType方法的函數)中,您將得到一個JSON值對象(任何toJSONValue返回的結果),並由您來完成。爲了更好地理解轉換過程,讓我們通過給出您的類的示例。

比方說,我們即將通過電線傳遞您的外部類的實例(例如作爲方法調用中的參數)。

myOuter = new Outer({innerHere: new Inner('inner value')}); 

流星將遵循類似步驟:

EJSON.stringify(myOuter) => 
    var jsonValue = EJSON.toJSONValue(myOuter); 
    var json = JSON.stringify(jsonValue); 

到EJSON.toJSONValue調用建立以$類型和$ value屬性的新對象。 $ value屬性的值是在對象上調用toJSONValue的結果。所以jsonValue是一個看起來像這樣的對象:

{ 
    $type: 'Outer', 
    $value: { 
    innerHere: { 
     value: 'inner value' 
    } 
    } 
} 

調用JSON。字符串化(jsonValue)的結果是JSON字符串,看起來像這樣:

"{"$type":"Outer","$value":{"value":{"innerHere":{"value":"inner value"}}}}" 

如果你想innerHere屬性是EJSON類型,我們需要調用EJSON.toJSONValue該對象以及(來自外部的toJSONValue方法)。例如(在JS):

Outer.prototype.toJSONValue = function() { 
    return { 
    value: EJSON.toJSONValue(this.value) 
    }; 
}; 

現在讓我們說,我們創建外的新實例是這樣的:

myOuter = new Outer(new Inner('inner value')); 

然後我們調用EJSON.toJSONValue(myOuter):

{ 
    $type: 'Outer', 
    $value: { 
    value: { 
     $type: 'Inner', 
     $value: { 
     value: 'inner value' 
     } 
    } 
    } 
} 

通過電線發送的結果json字符串如下所示:

"{"$type":"Outer","$value":{"value":{"$type":"Inner","$value":{"value":"inner value"}}}}" 

好吧,現在我們的fromJSONValue函數會發生什麼?我們將得到一個與JSONValue返回的內容類似的對象。因此,在將它們傳遞給Outer的構造函數之前,我們需要在每個我們知道是自定義類型的屬性上調用EJSON.fromJSONValue。在這個例子中,你可以這樣做:

EJSON.addType('Outer', function (jsonValue) { 
    var inner = EJSON.fromJSONValue(jsonValue.value); 
    return new Outer(inner); 
}); 

你可以用它來測試序列化和反序列化的兩種方法是:

var serialized = EJSON.stringify(myOuter); 
var deserialized = EJSON.parse(serialized); // is the resulting object what you expect? 

希望這有助於!

+0

非常有幫助的答案!最後的測試方法是一個非常好的主意 - 對於TDD EJSON代碼看起來很完美。 – rdickert

相關問題