4

私のアプリでは、1 つの coffeescript クラスを別のクラス内に作成しました ( のインスタンスには、プロパティの 1 つとして のclass Aインスタンスを持つオブジェクトの配列が含まれていますclass B)。その後、EJSON に関する cmather のビデオを発見し、それをオブジェクトで使用するのはクールだと思いました。ただし、Meteor は、他の EJSON オブジェクト内にある EJSON オブジェクトを正しく処理していないようです。class Aはデータストアに保存でき、照会すると として返されますclass Aclass B、コレクションからObjectではなくとして返されます。class B実例。collection.insert()いくつかのテスト コードを実行したところ、埋め込まれたEJSON オブジェクトは最初は (最初の.Objectまたは、ブラウザを更新した後の構造が正しくないオブジェクト。私の理論では、minimongo とサーバー側の mongo の動作にはいくつかの不一致がありますが、他の原因がある可能性があります。

では、ある EJSON オブジェクトを別のオブジェクトに埋め込む方法はありますか? おそらく私のコードに欠陥がありますか?それはただの悪い考えですか?でアイテム自体をclass Aインスタンス化することもできましたが、EJSON がこれを処理できるはずです。これがバグだと思われる場合は、喜んで github に問題を送信しますが、最初にここで確認することにしました。class Bconstructor

これを試すためのコードが必要な場合は、以下のコードを試すことができます。このコードは、2 つの本質的に同一のクラス (1 つは と呼ばれInner、もう1 つは と呼ばれます) をセットアップし、 のインスタンスをプロパティとして含むと呼ばれるOuterのインスタンスを作成します。コンソールで、 と入力します。現在、オブジェクトのプロパティが の適切なインスタンスであるオブジェクトが表示される場合がありますが、ブラウザを更新すると、同じコマンドが別のものを返す場合があります。OuterouterInnerinnerHeretestCollection.insert({outerHere: outer}testCollection.findOne()innerHereInner

この質問を理解するのが難しい場合は、お知らせください。明確にするよう努めます。

これを設定するコード (.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")})
4

1 に答える 1

4

EJSON が Outer 型の toJSONValue を呼び出すとき、内部型を自動的に検出するために結果に再帰することはありません。同様に、fromJSONValue (EJSON.addType メソッドに渡す関数) では、JSON 値オブジェクト (toJSONValue が返す結果) を取得しており、それを処理するのはユーザー次第です。変換プロセスをよりよく理解するために、指定されたクラスの例を見てみましょう。

Outer クラスのインスタンスをネットワーク経由で (メソッド呼び出しのパラメーターとして) 渡そうとしているとしましょう。

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

Meteor は次のような手順に従います。

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

EJSON.toJSONValue を呼び出すと、$type および $value プロパティを持つ新しいオブジェクトが作成されます。$value プロパティの値は、オブジェクトで toJSONValue を呼び出した結果です。したがって、jsonValue は次のようなオブジェクトです。

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

JSON.stringify(jsonValue) を呼び出すと、次のような JSON 文字列が生成されます。

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

innerHere プロパティを EJSON タイプにしたい場合は、そのオブジェクトでも EJSON.toJSONValue を呼び出す必要があります (Outer の toJSONValue メソッドから)。例(jsの場合):

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

ここで、次のように Outer の新しいインスタンスを作成するとします。

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 関数では何が起こるのでしょうか? toJSONValue が返すものに似たオブジェクトを取得します。そのため、Outer のコンストラクターに渡す前に、カスタム型であることがわかっている各プロパティで EJSON.fromJSONValue を呼び出す必要があります。この例では、次のようにします。

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

シリアル化と逆シリアル化をテストするために使用できる 2 つの方法は次のとおりです。

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

お役に立てれば!

于 2013-08-04T05:47:13.247 に答える