web-dev-qa-db-ja.com

Mongoose / MongoDBの結果フィールドがJavaScriptで定義されていないように見える

アイテムがパラメーター付きのオブジェクトとしてログに記録できるようにするために欠けているものはありますか?しかし、そのパラメーターにアクセスしようとすると、未定義ですか?

これまでに試したこと:

  • console.log(item) => _{ title: "foo", content: "bar" }_、それで結構です
  • console.log(typeof item) =>オブジェクト
  • console.log(item.title) => "未定義"

問題に関連する場合に備えて、コンテキストの一部を含めます。

_var TextController = function(myCollection) {
  this.myCollection = myCollection
}

TextController.prototype.list = function(req, res, next) {
  this.myCollection.find({}).exec(function(err, doc) {
    var set = new Set([])
    doc.forEach(function(item) {
      console.log(item)         // Here item shows the parameter
      console.log(item.title)   // "undefined"
      set.add(item.title)       
    })
    res.json(set.get());
  })
}
_

提案に基づいて、この行の前にdebuggerをドロップして、ノードのreplデバッガーを介して実際にどの項目があるかを確認しました。これは私が見つけたものです: http://hastebin.com/qatireweni.sm

これから私はconsole.log(item._doc.title)を試してみましたが、うまく機能します。つまり、これは何よりもマングースの質問のように思えます。

これに似た質問がありますが、オブジェクトへの「これ」のアクセスに関連しているようであるか、関数のスコープ外にオブジェクトを取得しようとしています。この場合、どちらもやっているとは思いませんが、間違っている場合はお知らせください。ありがとう

28
tippenein

解決

フィールドにアクセスするためにtoObjectメソッドを呼び出すことができます。例えば:

_var itemObject = item.toObject();
console.log(itemObject.title); // "foo"
_

なぜ

あなたが指摘するように実際のフィールドはドキュメントの__doc_フィールドに保存されます

しかし、なぜconsole.log(item) => _{ title: "foo", content: "bar" }_なのか?

mongoose(document.js)のソースコード から、toStringDocumentメソッドがtoObjectメソッドを呼び出すことがわかります。したがって、_console.log_はフィールドを「正しく」表示します。ソースコードを以下に示します。

_var inspect = require('util').inspect;

...

/**
 * Helper for console.log
 *
 * @api public
 */
Document.prototype.inspect = function(options) {
  var isPOJO = options &&
    utils.getFunctionName(options.constructor) === 'Object';
  var opts;
  if (isPOJO) {
    opts = options;
  } else if (this.schema.options.toObject) {
    opts = clone(this.schema.options.toObject);
  } else {
    opts = {};
  }
  opts.minimize = false;
  opts.retainKeyOrder = true;
  return this.toObject(opts);
};

/**
 * Helper for console.log
 *
 * @api public
 * @method toString
 */

Document.prototype.toString = function() {
  return inspect(this.inspect());
};
_
34
Vincent Bel

スキーマにタイトルが定義されていることを確認してください:

var MyCollectionSchema = new mongoose.Schema({
    _id: String,
    title: String
});

for initemをループして、値にアクセスできるかどうかを確認します。

for (var k in item) {
    console.log(item[k]);
}

機能する場合は、キーにnon-printable文字またはこのようなもの。

あなたがコメントで言ったことから、何とかitemStringプリミティブラッパーのインスタンスのようです。

例えば。

var s = new String('test');
typeof s; //object
s instanceof String; //true

この理論を検証するには、次のことを試してください。

eval('(' + item + ')').title;

また、itemは、表示内容を表示するtoStringメソッドを持つオブジェクトである可能性もあります。

編集:これらの問題をすばやく特定するには、console.dir の代わりに console.log、オブジェクトプロパティのインタラクティブなリストを表示するため。ブレークポイントとウォッチを追加することもできます。

4
plalx

'find'メソッドを使用すると、Documentsの配列が返されると思います。これを試したところ、タイトルを印刷できました。

for (var i = 0; i < doc.length; i++) {
   console.log("iteration " + i);
   console.log('ID:' + docs[i]._id);
   console.log(docs[i].title);
}
2
bertanasco

_' title'_に空白や変な文字がありませんか?オブジェクト/マップ定義に識別子を引用した場合、それらを定義できます。例えば:

_var problem = {
    ' title': 'Foo',
    'content': 'Bar'
};
_

これにより、console.log(item)が期待どおりに表示される可能性がありますが、undefinedプロパティに先行スペースなしでアクセスすると、title問題が発生します。

2
Thomas W

古い質問ですが、私もこれに問題があったので、答えます。
これは、find()ではなくfindOne()を使用しているために発生した可能性があります。つまり、最終的には、ドキュメントではなくドキュメントの配列のメソッドを呼び出しているため、単一のドキュメントではなく配列が検出されます。 findOne()を使用すると、通常どおりオブジェクトにアクセスできます。

2
user5887278

すべてのマングースの利点なしで情報を取得したいだけの場合は、保存してください。つまり、クエリで.lean()を使用できます。それはあなたの情報をより速く取得し、あなたはそれを直接オブジェクトとして使うことができます。

https://mongoosejs.com/docs/api.html#query_Query-lean

ドキュメントで言うように、これは読み取り専用のシナリオに最適です。

1
LordRasta

findOne()の代わりにfind()を使用します。

find()メソッドは値の配列を返します。結果が1つしかない場合でも、それを取得するにはitem [0]を使用する必要があります。

findOneメソッドは1つのオブジェクトを返すか、何も返さないため、問題なくそのプロパティにアクセスできます。

1
George

このような問題に取り組むより良い方法は、このようにdoc.toObject()を使用することです

doc.toObject({ getters: true })

その他のオプションは次のとおりです。

  • getters:すべてのゲッター(パスおよび仮想ゲッター)を適用します
  • virtuals:仮想ゲッターを適用します(ゲッターオプションをオーバーライドできます)
  • minimize:空のオブジェクトを削除(デフォルトはtrue)
  • transform:返される前に結果のドキュメントに適用する変換関数
  • depopulate:設定済みのパスを設定解除し、元の参照で置き換えます(デフォルトはfalse)
  • versionKey:バージョンキーを含めるかどうか(デフォルトはtrue)

だから例えばあなたは言うことができます

Model.findOne().exec((err, doc) => {
   if (!err) {
      doc.toObject({ getters: true })
      console.log('doc _id:', doc._id) // or title
   }
})

そして今それは動作します

1
Jalasem

オブジェクトを初期化していますか?

function MyObject()
{
    this.Title = "";
    this.Content = "";
}

var myo1 = new MyObject();

初期化しない、またはタイトルを設定していない場合。未定義になります。

0
Valamas