Mongoose: Document.toObject()メソッドを使用してすべてのObjectIdを文字列に変換しますか?

作成日 2015年03月25日  ·  24コメント  ·  ソース: Automattic/mongoose

ドキュメント内の_idは、toObject()の後もObjectIdであることがわかりました。

これを達成する方法はありますか?

help

最も参考になるコメント

モンゴのこの機能は本当に残念です

全てのコメント24件

同じバグがあります。 toJSON()toObject()はどちらも、 ObjectIdインスタンスを文字列化しません。

ObjectIdは技術的には文字列ではないため、これは現在の設計によるものです。 私が考えることができる唯一の方法は、頭のてっぺんからJSON.parse(JSON.stringify(doc));にすることです。すべてのオブジェクトIDを文字列化するためのユースケースは何ですか?

したがって、関数toJSON()はオブジェクトをJSON文字列に変換しませんか? _idと日付は文字列ではなくオブジェクトですか?

ちなみに、 toObject()toJSON()の違いは何ですか?
どうも!

ええ、日付はtoJSON() + toObject()の後の文字列ではなく、日付である必要があります。

toJSON()toObject()は基本的に同じですが、唯一の違いは、 JSON.stringify(doc)を実行すると、JavaScriptがドキュメントでtoJSON()関数を検索し、それを使用して変換することです。物体。 したがって、 toJSON()の理由は、 JSON.stringify()のシンタックスシュガーです。

@ vkarpov15クローズされた問題についてコメントして申し訳ありませんが、この問題に直接関連しているため、投稿するのに最も適切な場所のようです。

2つのマングースドキュメントを深く比較して、それらの間の変更の差分オブジェクトを取得しようとしています。
ただし、ObjectIDを直接比較することはできないようです。これは、まったく同じIDが含まれている場合でも、常に差分が返されるためです。

私がこれまでにそれを行うことができた唯一の方法は、これを行うことです:

var objectdiff = require('object-deep-diff');

var diffresult = objectdiff(
  JSON.parse(JSON.stringify(doc1.toObject())),
  JSON.parse(JSON.stringify(doc2.toObject()))
);

これは、オブジェクト間の差分を取得するための高価な方法のようです。
マングースのドキュメントを確実に比較するためのより良い方法を知っていますか?

差分がどの程度深く機能するかはわかりませんが、mongodbObjectIdsでいくつかの問題が発生している可能性があります。 _idおよびその他のobjectidフィールドを文字列に変換してみてください。 または、lodashの深い同等性チェックを使用するだけで、ObjectIdsで機能すると思います

@ vkarpov15 deep diffは等価性チェックにlodashを使用するため、残念ながらそれは機能しません。
https://github.com/rbs392/object-deep-diff/blob/master/index.js

すべてのObjectIdを文字列に変換することは機能しますが、オブジェクトには配列やその他のネストされたオブジェクトを含めることができるため、これも非常にコストのかかる作業になります。

では、別の質問がありますtoObject()の結果である2つのマングースドキュメントまたは2つのドキュメントでdeep-diffを使用していますか? 後者は機能するはずですが、前者はそれほど機能しません。

@ vkarpov15通常は1つのマングースドキュメント(.toObjectでjavscriptオブジェクトに変換)と1つの通常のjavascriptオブジェクトです。
その理由は、クライアントからのデータを、すでにデータベースにあるデータと比較する必要があるためです。
したがって、クライアントからのデータにはすでにObjectIDが変換されていますが、データベースからのデータは変換されていません。
しかし、私はマングースプラグインでこの深い差分チェックを行っているので、両方のドキュメントが同じように構築されていることを絶対に確認する必要があります。そのため、JSON.parse(JSON.stringify(doc.toObject())を実行する必要があります。 )両方のドキュメントで。

そうです、その場合はJSON.parse(JSON.stringify())を実行する必要があります。これは、すべてのオブジェクトIDを文字列に変換する最も簡単な方法です。

JSON.parse(JSON.stringify())は私には計算量が多すぎたので、このパフォーマンスを考えたlibを作成する必要がありました。

var transformProps = require('transform-props');

function castToString(arg) {
    return String(arg);
}

var doc = new MongooseModel({ subDoc: { foo: 'bar' }});
var docObj = doc.toObject();

transformProps(docObj, castToString, '_id');

console.log(typeof docObj._id); // 'string'
console.log(typeof docObj.subDoc._id); // 'string'

モンゴのこの機能は本当に残念です

@ZacharyRSmithでは、他の小道具についてはどうでしょうか。 author_id(ObjectIdはユーザーモデルを参照します)/ author_ids(ObjectIdsの配列)?

@ Flight9は、transformProps()に複数のキーを探すように指示できます。 こちらのテストをご覧ください: https ://github.com/ZacharyRSmith/transform-props/blob/master/index.test.js#L67

私はあなたがこれであなたが望むものを手に入れることができると信じています:

function myToString(val) {
  if (Array.isArray(val)) {
    return val.map(item => String(item));
  }
  return String(val);
}

transformProps(obj, myToString, ['author_id', 'author_ids']);

@ZacharyRSmithあなたの解決策をありがとう、それは素晴らしいです!

重要なことを1つ見逃したと思います。私が書いているツールは、プロジェクト内のすべてのモデルに適用する必要があるため、どのフィールドがObjectIdであるかを事前に把握していません。これは、複数のObjectIdフィールドがある場合とない場合があり、そのフィールド名です。不確定です。
それで、数時間試した後、私は私の解決策を持っています:

const ObjectID = require('mongodb').ObjectID;

/**
 * Convert ObjectId field values inside an object to String type values
 * (includes array of ObjectIds and nested ObjectId fields)
 * <strong i="9">@param</strong> obj Object - The Object to be converted.
 * <strong i="10">@return</strong> none
 */
function objectIdtoString(obj) {
  for(let k in obj) {
    let v = obj[k];
    if(typeof v == 'object') {
      if(k.endsWith('_id') && v instanceof ObjectID) {
        obj[k] = v.toString();
      }
      else if(
        k.endsWith('_ids') && Array.isArray(v) &&
        v.length > 0 && v[0] instanceof ObjectID
      ) {
        let vs = [];
        for(let iv of v) {
          vs.push(iv.toString());
        }
        obj[k] = vs;
      }
      else {
        objectIdtoString(v);
      }
    }
  }
}

// Call example
objectIdtoString(obj):

@ vkarpov15

その場合は、JSON.parse(JSON.stringify())を実行する必要があります。これは、すべてのオブジェクトIDを文字列に変換する最も簡単な方法です。

https://medium.com/ft-product-technology/this-one-line-of-javascript-made-ft-com-10-times-slower-5afb02bfd93f

tldr; JSON.parse(JSON.stringify())は同期的なブロックタスクであり、深刻なボトルネックを引き起こす可能性があります。 これは、この問題に対して受け入れられた/提案された解決策ではありません...

mongoose.Types.ObjectId.prototype.toJSON = function() { return this.toString();も実行できるはずです。 しかし、その記事でさえ、JSON.parse(JSON.stringify)はディープクローンを作成するより高速な方法の1つであり、問​​題は、不必要にディープクローンを繰り返し実行していたことでした。

だから、これが2019年です。
オブジェクト上のすべてのObjectIdインスタンスから16進文字列を取得するための、すてきでクリーンで明白な方法はまだありますか?

@gitowiec

mongoose.ObjectId.get(v => v.toString());

参照: http: //thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration.html#schematype -getters

@ vkarpov15は、「リーン」を使用する場合、これは解決策ではないようです。
したがって、目的の結果が文字列objectIdsを持つプレーンなjsonオブジェクトを返すことである場合、これを実現する最も効率的な方法は、 leanオプションでJSON.parse(JSON.stringify())を使用することです。

またはおそらく無駄のないプラグイン: https ://www.npmjs.com/package/mongoose-lean-objectid-string

@nhitchins正解です。mongoose -lean- gettersのようなプラグインを使用する必要があります。

@ vkarpov15これもディスクリミネータースキーマで機能するはずですか? バリアントを作成するための基本スキーマがあります。 基本スキーマにゲッターを設定してみました。 私はlean()を使用し、mongoose-lean-gettersを使用しましたが、これを機能させることができませんでした。

@pwrnrd新しい問題を開いて、問題テンプレートに従ってください。 ディスクリミネータースキーマで正常に動作するはずです。

このページは役に立ちましたか?
0 / 5 - 0 評価