get _id with mongoose - javascript

I was trying to console.log(record._id) all of records on my mongodb collection using Mongoose. I kept getting undefined for each of the _id values.
I struggled until I bumped into this post. Then I used console.dir to find the location of the _id and used that in my console.log:
MySchemaModel.find({}).then(function(records) {
records.forEach(function(record) {
console.log(record._doc._id); // <-- I added ._doc
});
});
But, this looks down-right hacky. Is there a better way to do this?
NOTE: This isn't just something that affects console.log. I'm just keeping the question narrow.

If you want to customize/edit record then you should use .lean() function.The .lean() function will turn it into a normal JavaScript object. If you don't use .lean() function then each record is still a mongoose document and _id behaves differently in that context. So can use like
MySchemaModel.find({}).lean().exec(function(error, records) {
records.forEach(function(record) {
console.log(record._id);
});
});
N.B: when use .exec() then first parameter used for error and second one for success data.

Mongoose assigns each of your schemas an id virtual getter by default
which returns the documents _id field cast to a string, or in the case
of ObjectIds, its hexString. If you don't want an id getter added to
your schema, you may disable it passing this option at schema
construction time.
Source: Mongoose Docs
var schema = new Schema({ name: String }, { id: false });
var Page = mongoose.model('Page', schema);
var p = new Page({ name: 'mongodb.org' });
console.log(p.id); // '50341373e894ad16347efe01'

I guess the issue is with .then promise, I have never seen that.
MySchemaModel.find({}).then
So just try simple .exec call with callback.
MySchemaModel.find({}).exec(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});

The problem is that each record is still a mongoose document and _id behaves differently in that context. The .lean() function will turn it into a normal JavaScript object.
MySchemaModel.find({}).lean().then(function(records) {
records.forEach(function(record) {
console.log(record._id);
});
});

you can also use the .map() method :
MySchemaModel.find({}).exec(function(records) {
console.log(records.map(record => record._id);
});

if you are using a model you don't get the full object but an instance of _doc as record
so you should directly
console.log(record._id)
or
console.log(record._id.valueOf())
but when you return record as response you get the full object so it's better to use .find().lean()

Related

MongoDB findOne() for retrieving from DB

I am writing code in nodejs/MongoDB and am countering this particular issue which I was hoping to get help with:
I have various schemas defined within my Models and I note that for each of these MongoDB automatically populates a unique id, which is represented by the _id field.
However, I am interested in creating a customized ID, which is basically an integer that auto-increments. I have done so by utilizing the 'mongoose-auto-increment' npm package. For example, in my UserSchema:
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
autoIncrement.initialize(mongoose.connection);
UserSchema.plugin(autoIncrement.plugin, {
model: 'UserSchema',
field: 'user_id',
startAt: 1,
incrementBy: 1
});
To speed up my application, I have a seeds.js file which aims to load a bunch of data upon application initialization. However, to make this fully functional, I need a way to access my models and reference them over to other models (for cases when there is a one-to-one and one-to-many relationship). Since the mongoDB default _id is extremely long and there is no way to get the result unless I am actually on the html page and can use the req.params.id function, I have been trying to use mongoDB's findOne function to do this without success.
For example:
var myDocument = User.findOne({user_id: {$type: 25}});
if (myDocument) {
var myName = myDocument.user_id;
console.log(myName);
}
However, the result is always 'undefined' even though I know there is a User model saved in my database with a user_id of 25.
Any help would be much appreciated :)
User.findOne({ user_id: 25 }).exec(function (err, record) {
if (err) {
console.log(err);
} else {
console.log(record);
}
});
You need to undestand the nature of Node.js.
Node.js runs in async nature so you can't get the result here.
You need to do with other ways
like:
use callback
use promise
use async/await(ES8)
Try this:
User.findOne({user_id: {$type: 25}}, function (err, myDocument) {
if (myDocument) {
var myName = myDocument.user_id;
console.log(myName);
} else {
console.log(err);
}
});

adding a new property to existing doesn't work

I'm trying to add another property to existing object returning from findOne() promise in mongoose.
In the response I get the object without the property convertName
app.get('/getItem', (req, res) => {
var itemID = req.query.itemID;
Item.findOne({_id: itemID}).then(item => {
item.convertName = 'cm';
res.send(item);
}).catch( err => {
res.status(401).send();
});
})
I know that the way to add another property to an existing object is similar to this, just specify the property name and set a value to it, so I don't know why it is not working in this case.
Hope you can explain and help me why its not working.
It's a bit complicated with Mongoose: by default MongooseDocument is returned by query, and the property that you try to add to such a document is not reflected on its serialized value (the one that is sent in the response).
One possible way around this is using lean() method to enable lean option. Quoting the doc:
Documents returned from queries with the lean option enabled are plain
javascript objects, not MongooseDocuments. They have no save method,
getters/setters or other Mongoose magic applied.

Stripped Attributes with toJSON/toObject

I have something like the following code:
User.findOne(id)
.exec((err, user) => {
Pets.find(_.pluck(user.pets, 'id'))
.populate("toys")
.exec((err, petsWithToys) => {
user.pets = petsWithToys;
return res.ok({ user: user });
});
});
When I look at the response in the client I don't see the toys array inside the pet.
I thought maybe this was due to overriding the toJSON function in my User model but even when removing it I get the same behavior.
Also, I've found out that if I assign the values to a new property that is not defined in the model, I do see the values at the client. I.e. if I do
user.petsNew = petsWithToys;
I will see the fully populated property.
I've seen the documentation of toObject where is says it removes instance methods (here) but I am not sure why the collection is considered a method and don't understand how after changing the value it is still removed.
Any comments/explanations/workarounds?
P.S. Tried to step through the code but can't step into toObject...
Add user = user.toJSON(); before user.pets = petsWithToys;
Check https://stackoverflow.com/a/43500017/1435132

Mongo: find by ObjectId is not defined in meteor?

I am using existing Mongodb in meteor project. The existing mongo id represented by ObjectId(). When I try to find by _id, Meteor says ObjectId is not defined
JS:
Names = new Mongo.Collection('name_list', {idGeneration: 'MONGO'});
Names.find({"_id" : ObjectId("5539d9dcf046be5b2302aefc")}) //ReferenceError: ObjectId is not defined
The above JavaScript code is run in server.
You have to use new Mongo.ObjectID("5539d9dcf046be5b2302aefc"). See the meteor docs for some caveats.
If you want to save having to type new and Mongo. each time, you can define a function:
function ObjectId(hexString) { return new Mongo.ObjectID(hexString); };
and then the code you wrote will work.
You just need to require the ObjectId function from your mongo.
ObjectId = require('mongodb').ObjectID;
Then you can use it like that:
ObjectId("5539d9dcf046be5b2302aefc")
If you are using mongojs:
db.mycollection.findOne({
_id: mongojs.ObjectId('your object id')
}, function(err, doc) {
//do your stuff here.
})

Saving a modified document (with a modified subdocument array) in Mongoose model

The code I currently have is:
User.findOne(
{
"subUsers.email" : userEmail
},
{
subUsers : {
$elemMatch: {
email : userEmail }
}
},
function(err, user){
if(user){
var information = user.subUsers[0].information.id(id);
information.arrayA.push({someId : "something"});
user.save(callback(err)); // Also tried information.save()
// without luck
}
callback(err);
}
);
This doesn't return any kind of error, but when I check the DB, the new array element hasn't been pushed (the whole document is intact).
Any help would be much appreciated. Thanks!
You should probably check out the first faq, here: http://mongoosejs.com/docs/faq.html
Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets
notified of the change and so doesn't know to persist the new value. The work-around is to
use [MongooseArray set][1] available in Mongoose >= 3.2.0.
So in your case, you want to add this third line
var information = user.subUsers[0].information.id(id);
information.arrayA.push({someId : "something"});
user.subUsers.set(0, information);
Or something like that.
As of today, Mongoose is currently not prepared for multilevel nesting in an atomic way.
Therefore, even if it's going back to a kind-of relational database, in this case it's better to split the nesting into at least 2 collections, and reference using the automatically generated ObjectId.

Categories