What is the difference between Model.findOne() & Model.findById() in Mongoose? - node.js

Consider we are searching a document from MongoDB based on the _id value. Which one of the following code is efficient ?
ModelObj.findById(IdValue).exec(callback);
ModelObj.findOne({ '_id': IdValue}).exec(callback);
I feel ModelObj.findById() is efficient, but what are the supportive reasons or How is it efficient?

findById is just a convenience function that does exactly the same thing as the findOne call you show.
Here's the source:
Model.findById = function findById (id, fields, options, callback) {
return this.findOne({ _id: id }, fields, options, callback);
};

findById(id) is almost equivalent to findOne({ _id: id }).
If you want to query by a document's _id, use findById() instead of findOne().
Both functions trigger findOne(), the only difference is how they treat undefined.
If you use findOne(), you'll see that findOne(undefined) and findOne({ _id: undefined }) are equivalent to findOne({}) and return arbitrary documents.
However, mongoose translates findById(undefined) into findOne({ _id: null }).
See https://mongoosejs.com/docs/api.html#model_Model.findById
Here's the source:
Model.findById = function findById(id, projection, options, callback) {
if (typeof id === 'undefined') {
id = null;
}
if (callback) {
callback = this.$wrapCallback(callback);
}
return this.findOne({_id: id}, projection, options, callback);
};

findById(id) is just syntactic sugar of the find({_id : id}) or findOne({_id: id})

Using .findOne makes the database look through its records checking each bson document to find the relevant variable and then check the value, if mongo knows its looking for the internally indexed _id field it doesn't have to look through each document

Related

Mongoose deleteMany using _id on nodejs

i have a ids of array ['123','456', '789']. i want delete all this array in mongodb
How i user it:
ScheduleModel.deleteOne({ _id: ['123','456', '789'] });
this is not working because this is not object Id
what i Need :
ScheduleModel.deleteOne({ _id: [ObjectId('123'), ObjectId('456'), ObjectId('789')] });
How to add object Id in array data. any how to resolve this issues. i need a solution on this.
It's not about ObjectId. you are using wrong syntax. You must use $in statement
ScheduleModel.deleteMany({ id: { $in: ['123','456','789'] } });
Use deleteMany with proper syntax.When there are many objectId at time Use $in.
Try this :
var deleteCondition = {
_id : {
//In Array you can pass your objectId
$in : ['123','456','789']
}
//You can pass other conditions
}
//deleteMany
ScheduleModel.deleteMany(deleteCondition, function (err, res) {
if (res) console.log(res)
})

How to update some data based on array value in Mongoose?

I'd like to update some data in Mongoose by using array value that I've find before.
Company.findById(id_company,function(err, company) {
if(err){
console.log(err);
return res.status(500).send({message: "Error, check the console. (Update Company)"});
}
const Students = company.students;
User.find({'_id':{"$in" : Students}},function(err, users) {
console.log(Students);
// WANTED QUERY : Update company = null from Users where _id = Students[];
});
});
Students returns users._id in array with object inside, and I use that to find users object, and then I want to set null a field inside users object, that field named as "company". How I can do that? Thank you.
From what you posted (I took the liberty to use Promises but you can roughly achieve the same thing with callbacks), you can do something like:
User.find({'_id':{"$in" : Students}})
.then( users =>{
return Promise.all( users.map( user => {
user.company = null;
return user.save()
}) );
})
.then( () => {
console.log("yay");
})
.catch( e => {
console.log("failed");
});
Basically, what I'm doing here is making sure .all() user models returned by the .find() call are saved properly, by checking the Promised value returned for .save()ing each of them.
If one of these fails for some reasons, Promise.all() return a rejection you can catch afterhand.
However, in this case, each item will be mapped to a query to your database which is not good. A better strategy would be to use Model.update(), which will achieve the same, in, intrinsically, less database queries.
User.update({
'_id': {"$in": Students}
}, {
'company': <Whatever you want>
})
.then()
use .update but make sure you pass option {multi: true} something like:
User.update = function (query, {company: null}, {multi: true}, function(err, result ) { ... });

mongoose callback is not an array

In my models I have this
module.exports.getPhotosById = function(userId,callback){
Photos.findOne({userId:userId},callback);
}
Then in route I do
Photo.getPhotosById(req.user._id,function(err,result){
console.log(result);
console.log(result.length);
});
The first console output this
{ _id: 325657865435643245,
userId: '32443564',
photo: 'abc.jpg',
caption: 'abc'
}
but why it's not an array? because the second console's output is undefined.
result is a single document instead of an array because you're calling findOne, not find.
To get all of a user's photo docs, change your method to:
module.exports.getPhotosById = function(userId, callback){
Photos.find({userId: userId}, callback);
}
findone Returns one document(JSON) that satisfies the specified query criteria
find Returns the array of Objects.

Find and delete a field in mongodb using mongoose [duplicate]

I'm using the Mongoose Library for accessing MongoDB with node.js
Is there a way to remove a key from a document? i.e. not just set the value to null, but remove it?
User.findOne({}, function(err, user){
//correctly sets the key to null... but it's still present in the document
user.key_to_delete = null;
// doesn't seem to have any effect
delete user.key_to_delete;
user.save();
});
In early versions, you would have needed to drop down the node-mongodb-native driver. Each model has a collection object that contains all the methods that node-mongodb-native offers. So you can do the action in question by this:
User.collection.update({_id: user._id}, {$unset: {field: 1 }});
Since version 2.0 you can do:
User.update({_id: user._id}, {$unset: {field: 1 }}, callback);
And since version 2.4, if you have an instance of a model already you can do:
doc.field = undefined;
doc.save(callback);
You'll want to do this:
User.findOne({}, function(err, user){
user.key_to_delete = undefined;
user.save();
});
I use mongoose and using any of the above functions did me the requirement. The function compiles error free but the field would still remain.
user.set('key_to_delete', undefined, {strict: false} );
did the trick for me.
At mongo syntax to delete some key you need do following:
{ $unset : { field : 1} }
Seems at Mongoose the same.
Edit
Check this example.
Try:
User.findOne({}, function(err, user){
// user.key_to_delete = null; X
`user.key_to_delete = undefined;`
delete user.key_to_delete;
user.save();
});
if you want to remove a key from collection try this method.
db.getCollection('myDatabaseTestCollectionName').update({"FieldToDelete": {$exists: true}}, {$unset:{"FieldToDelete":1}}, false, true);
Could this be a side problem like using
function (user)
instead of
function(err, user)
for the find's callback ? Just trying to help with this as I already had the case.
Mongoose document is NOT a plain javascript object and that's why you can't use delete operator.(Or unset from 'lodash' library).
Your options are to set doc.path = null || undefined or to use Document.toObject() method to turn mongoose doc to plain object and from there use it as usual.
Read more in mongoose api-ref:
http://mongoosejs.com/docs/api.html#document_Document-toObject
Example would look something like this:
User.findById(id, function(err, user) {
if (err) return next(err);
let userObject = user.toObject();
// userObject is plain object
});
the problem with all of these answers is that they work for one field. for example let's say i want delete all fields from my Document if they were an empty string "".
First you should check if field is empty string put it to $unset :
function unsetEmptyFields(updateData) {
const $unset = {};
Object.keys(updatedData).forEach((key) => {
if (!updatedData[key]) {
$unset[key] = 1;
delete updatedData[key];
}
});
updatedData.$unset = $unset;
if (isEmpty(updatedData.$unset)) { delete updatedData.$unset; }
return updatedData;
}
function updateUserModel(data){
const updatedData = UnsetEmptyFiled(data);
const Id = "";
User.findOneAndUpdate(
{ _id: Id },
updatedData, { new: true },
);
}
I believe that, if you desire remove a specific field into a collection, you should do this:
User.remove ({ key_to_delete: req.params.user.key_to_delete});
you can use
delete user._doc.key

How to use mongoose findOne

I have the below schema (apologies that it is in coffeescript)
Schema = mongoose.Schema
AuthS = new Schema
auth: {type: String, unique: true}
nick: String
time: Date
Auth = mongoose.model 'Auth', AuthS
I simply want to recover one record which is definitely in my database:
Auth.findOne({nick: 'noname'}, function(obj) { console.log(obj); });
Unfortunately this always logs null. db.auths.findOne({nick: 'noname'}) in mongo shell always returns a value. What is going on?
Found the problem, need to use function(err,obj) instead:
Auth.findOne({nick: 'noname'}, function(err,obj) { console.log(obj); });
Mongoose basically wraps mongodb's api to give you a pseudo relational db api so queries are not going to be exactly like mongodb queries. Mongoose findOne query returns a query object, not a document. You can either use a callback as the solution suggests or as of v4+ findOne returns a thenable so you can use .then or await/async to retrieve the document.
// thenables
Auth.findOne({nick: 'noname'}).then(err, result) {console.log(result)};
Auth.findOne({nick: 'noname'}).then(function (doc) {console.log(doc)});
// To use a full fledge promise you will need to use .exec()
var auth = Auth.findOne({nick: 'noname'}).exec();
auth.then(function (doc) {console.log(doc)});
// async/await
async function async auth() {
const doc = await Auth.findOne({nick: 'noname'}).exec();
return doc;
}
auth();
See the docs if you would like to use a third party promise library.
In my case same error is there , I am using Asyanc / Await functions , for this needs to add AWAIT for findOne
Ex:const foundUser = User.findOne ({ "email" : req.body.email });
above , foundUser always contains Object value in both cases either user found or not because it's returning values before finishing findOne .
const foundUser = await User.findOne ({ "email" : req.body.email });
above , foundUser returns null if user is not there in collection with provided condition . If user found returns user document.
You might want to consider using console.log with the built-in "arguments" object:
console.log(arguments); // would have shown you [0] null, [1] yourResult
This will always output all of your arguments, no matter how many arguments you have.
Use obj[0].nick and you will get desired result,

Resources