可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there something that I'm missing that would allow item to log as an object with a parameter, but when I try to access that parameter, it's undefined?
What I've tried so far:
console.log(item)
=> { title: "foo", content: "bar" }
, that's fine
console.log(typeof item)
=> object
console.log(item.title)
=> "undefined"
I'll include some of the context just in case it's relevant to the problem.
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());
})
}
Based on suggestion I dropped debugger
before this line to check what item actually is via the node repl debugger. This is what I found : http://hastebin.com/qatireweni.sm
From this I tried console.log(item._doc.title)
and it works just fine.. So, this seems more like a mongoose question now than anything.
There are questions similar to this, but they seem to be related to 'this' accessing of objects or they're trying to get the object outside the scope of the function. In this case, I don't think I'm doing either of those, but inform me if I'm wrong. Thanks
回答1:
Solution
You can call the toObject
method in order to access the fields. For example:
var itemObject = item.toObject();
console.log(itemObject.title); // "foo"
Why
As you point out that the real fields are stored in the _doc
field of the document.
But why console.log(item)
=> { title: "foo", content: "bar" }
?
From the source code of mongoose(document.js), we can find that the toString
method of Document
call the toObject
method. So console.log
will show fields 'correctly'. The source code is shown below:
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());
};
回答2:
Make sure that you have defined title in your schema:
var MyCollectionSchema = new mongoose.Schema({
_id: String,
title: String
});
回答3:
Try performing a for in
loop over item
and see if you can access values.
for (var k in item) {
console.log(item[k]);
}
If it works, it would mean your keys have some non-printable
characters or something like this.
From what you said in the comments, it looks like somehow item
is an instance of a String
primitive wrapper.
E.g.
var s = new String('test');
typeof s; //object
s instanceof String; //true
To verify this theory, try this:
eval('(' + item + ')').title;
It could also be that item
is an object that has a toString
method that displays what you see.
EDIT: To identify these issues quickly, you can use console.dir
instead of console.log
, since it display an interactive list of the object properties. You can also but a breakpoint and add a watch.
回答4:
You don't have whitespace or funny characters in ' title'
, do you? They can be defined if you've quoted identifiers into the object/map definition. For example:
var problem = {
' title': 'Foo',
'content': 'Bar'
};
That might cause console.log(item)
to display similar to what you're expecting, but cause your undefined
problem when you access the title
property without it's preceding space.
回答5:
I think using 'find' method returns an array of Documents.I tried this and I was able to print the title
for (var i = 0; i < doc.length; i++) {
console.log("iteration " + i);
console.log('ID:' + docs[i]._id);
console.log(docs[i].title);
}
回答6:
Old question, but since I had a problem with this too, I'll answer it.
This probably happened because you're using find()
instead of findOne()
. So in the end, you're calling a method for an array of documents instead of a document, resulting in finding an array and not a single document. Using findOne()
will let you get access the object normally.
回答7:
A better way to tackle an issue like this is using doc.toObject()
like this
doc.toObject({ getters: true })
other options include:
getters:
apply all getters (path and virtual getters)
virtuals:
apply virtual getters (can override getters option)
minimize:
remove empty objects (defaults to true)
transform:
a transform function to apply to the resulting document before returning
depopulate:
depopulate any populated paths, replacing them with their original refs (defaults to false)
versionKey:
whether to include the version key (defaults to true)
so for example you can say
Model.findOne().exec((err, doc) => {
if (!err) {
doc.toObject({ getters: true })
console.log('doc _id:', doc._id) // or title
}
})
and now it will work
回答8:
If you only want to get the info without all mongoose benefits, save i.e., you can use .lean() in your query. It will get your info quicker and you'll can use it as an object directly.
https://mongoosejs.com/docs/api.html#query_Query-lean
As says in docs, this is the best to read-only scenarios.
回答9:
Use findOne()
instead of find()
.
The find()
method returns an array of values, even if you have only one possible result, you'll need to use item[0] to get it.
The findOne
method returns one object or none, then you'll be able to access its properties with no issues.
回答10:
Are you initializing your object?
function MyObject()
{
this.Title = "";
this.Content = "";
}
var myo1 = new MyObject();
If you do not initialize or have not set a title. You will get undefined.