Mongoose - Increment with findOne - node.js

I'm working on some query with Mongoose where I need to skip and limit subdocuments, but in the same query I want to increment some field in document. Currently is my query built with chaining, because I got a lot of problem when I tried to do it just with options. This is what I have:
Model.findOne({ shorten_id: id }).select('title content comments views').slice('comments', [0, 10]).exec(function(err, db_res) { if (err) { throw err; } else { console.log(db_res); } });
I would like to increment filed 'views' for 1 when calling this query, but as I said, I tried a lot of things and it just didn't work.

You can use findOneAndUpdate to modify a document while also fetching one.
Model.findOneAndUpdate({ shorten_id: id }, { $inc: { fieldToIncrement: 1 })
.select('title content comments views')
.slice('comments', [0, 10])
.exec(function(err, db_res) {
if (err) {
throw err;
}
else {
console.log(db_res);
}
});

Related

mongoose: findOne using mongo _id

I get that this can be a duplicated question. I looked up at least 10 related questions and answers, but I am still not able to find the document.
I am trying to get the document using .findOne(). I have the _id that created by MongoDB. But, I get null for every search I try.
await mongoose.connection.db
.collection('testing')
.findOne({ _id: req.body.test_id }, (err, result) => {
if (err) {
res.status(400);
} else {
console.log(`whaaaaaahsidufh ${result}`);
}
});
I tried _id: mongoose.Type.ObjectId(req.body.test_id) and other possible way to search. How can I retrieve the result by using _id on mongoose?
you can use findById();
try {
const test = await mongoose.connection.db.collection('testing').findById(req.body.test_id);
if (test ) {
console.log(`whaaaaaahsidufh ${test}`);
} else {
console.log(`test not found`);
}
}catch(err){
res.status(400);
}

Selecting only modified subdocument from Mongo

I have a mongoose query like this:
var query = Events.findOneAndUpdate({ '_id': event._id,'participants._id':participant._id},{'$set': {'participants.$': participant}}, {upsert:false,new: true},function(err,result){
if(err){
return res.status(500).jsonp({
error: 'Unable to update participant'
});
}
console.log(result.participants[0]);
res.jsonp(result.participants[0]);
});
and the query works properly modifying the participants subdocument inside Events collection.
The problem:
I need only the modified participant to be returned as JSON and I am not in need of the entire participants array but I am not able to achieve this since I get all the participants when I do console.log(result.participants);
How do I get only the modified subdocument after the query?
You may have to use the native JS filter() method as in the following:
Events.findOneAndUpdate(
{ '_id': event._id, 'participants._id': participant._id },
{ '$set': { 'participants.$': participant } },
{ upsert: false, new: true },
function(err, result){
if(err){
return res.status(500).jsonp({
error: 'Unable to update participant'
});
}
var modified = result.participants.filter(function(p){
return p._id === participant._id
})[0];
console.log(modified);
res.jsonp(modified);
}
);

MongoDB $push operator not working as expected in Node

So I have a fairly simple piece of code as follows
db.get().collection('bars').insert({
barID: req.body.button,
}, {
$push: {
usersfbID: req.body.profileUser[0].facebookID
}
}, function(err, doc) {
if (err) {
throw err;
}
if (doc) {
console.log('Had to create a new document for this bar');
console.log(doc);
//callback(null, doc);
}
});
So, I'm just checking to see if a document for a bar exists, and if it doesn't then I create that document. And I want to insert an array for the usersfbID field so that I can store all the users going to the bar.
However, when I run the code, I don't get an error and it says the document has inserted but when the document logs, it doesn't have the userfbID field.
So what am I doing wrong? Does the $push operator only work with the update method of db? If so, how do I insert an array for that field?
Yes, it does work with the update methods
Reference > Operators > Update Operators > Array Update Operators > $push
Inserting a new entry means feeding the fields. In that case, there's no $push operation, since the array of the entry is freshly created and can be explicitly set (usersfbID:[req.body.profileUser[0].facebookID], meaning that you expect several fbId for that bar). Updating an array in an element of a collection isn't an insertion, it's an update.
So, just to provide an answer to the question I was facing..
Yes, you can only use $push or $addToSet with an update operation on a mongoDB document
Here is the way I implemented the code.
db.get().collection('bars').update({
barID: req.body.button,
}, {
$addToSet: {
usersfbID: req.body.profileUser[0].facebookID,
usersDocID: req.body.profileUser[0]._id
}
}, {
upsert: true
}, function(err, doc) {
if (err) {
console.log('There is an error here');
throw err;
}
if (doc) {
console.log('Had to create a new document for this bar');
callback(null, doc);
}
});
The upsert: true makes sure to insert a new document if the update method couldn't find the specified document.

Fetch entries from mongodb using mongoose

I am using mongoose to operate mongodb in node. And now I have to query entries from Post table where tags doesn't contain any tag like inc:___, inc:gdc, exc:abc, exc:57uyht7, all others tags are allowed like(test,card,check).
PostModel.Post.find({
$where:this.activeFlag==true && (this.tags!= null && this.tags != /^inc:/ && this.tags !=/^exc:/)
}), function(err, stack) {
if (!err) {
logger.debug('Posts found successfully.');
} else {
logger.error('Problem in finding posts, error :' + err);
}
});
But this is not working.. My query fetches entries with inc:dbgh also.
Can anyone help me?
Thanks in advance.
According to Mongo docs, you should pass either a string or javascript function to $where, and you pass javascript expression, which gets evaluated in place.
Also, your query can be simplified to
PostModel.Post.find({
activeFlag: true,
tags: {
$exists: true,
$not: /^(inc:|ecx:)/
}
}, function(err, stack) {
if (!err) {
logger.debug('Posts found successfully.');
} else {
logger.error('Problem in finding posts, error :' + err);
}
});

How to check if Mongo's $addToSet was a duplicate or not

I am using Mongoskin + NodeJS to add new keywords to MongoDB. I want to notify the user that the entry was a duplicate but not sure how to do this.
/*
* POST to addkeyword.
*/
router.post('/addkeyword', function(req, res) {
var db = req.db;
db.collection('users').update({email:"useremail#gmail.com"}, {'$addToSet': req.body }, function(err, result) {
if (err) throw err;
if (!err) console.log('addToSet Keyword.' );
});
});
The result does not seem to be of any use since it doesn't state if the keyword was added or not.
At least in the shell you can differentiate if the document was modified or not (see nModified).
> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.test4.update({_id:2}, {$addToSet: {tags: "xyz" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
Update for Node
When you use collection.update(criteria, update[[, options], callback]); you can retrieve the count of records that were modified.
From the node docs
callback is the callback to be run after the records are updated. Has
two parameters, the first is an error object (if error occured), the
second is the count of records that were modified.
Another Update
It seems at least in version 1.4.3 the native Mongo Node driver is not behaving as documented. It is possible to work around using the bulk API (introduced in Mongo 2.6):
var col = db.collection('test');
// Initialize the Ordered Batch
var batch = col.initializeOrderedBulkOp();
batch.find({a: 2}).upsert().updateOne({"$addToSet": {"tags": "newTag"}});
// Execute the operations
batch.execute(function(err, result) {
if (err) throw err;
console.log("nUpserted: ", result.nUpserted);
console.log("nInserted: ", result.nInserted);
console.log("nModified: ", result.nModified); // <- will tell if a value was added or not
db.close();
});
You could use db.users.findAndModify({email:"useremail#gmail.com"},[],{'$addToSet': { bodies: req.body }},{'new':false}). Pay attention to new:false switcher, it allows you to get document before update and you could check whether array contained item before update. However, it could be problematic approach if your documents are big, because you analyze it on client side.
P.S. Your original query with $addToSet is wrong: field name is missing.
Edit: I tried to use count returned by update, but it returns 1 for me in all cases. Here is the code I used for test with MongoDB 2.6:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/mtest', function(err, db) {
if(err) throw err;
db.collection('test').insert({_id:1,bodies:["test"]},function(err,item){
db.collection('test').update({_id:1},{$addToSet:{bodies:"test"}}, function(err,affected){
if(err) throw err;
console.log(affected); //1 in console
});
});
});
i am update a array from Collection with this JSON:
{
"<arrayname>":"<value>"
}
route.js
routes.post("/api/:id", Controller.addOne);
Controller.js
async addOne(req, res) {
//juryman id to list add
if (Object.keys(req.body).length === 1) {
console.log("Size 1");
}
await Session.findOneAndUpdate(
{ _id: req.params.id },
{ $addToSet: req.body }
)
.then(function(success) {
res.send("Successfully saved.");
})
.catch(function(error) {
res.status(404).send(error);
});
},
I have five arrays in my Collection and this changes the JSON array name-value and updates correctly, the respectively Collection array. This works only for one item.

Resources