MongoDB, increment field with condition - node.js

Is it possible, using mongoose middleware, to increment two fields one with a condition and the other without? In this case i want to increment "stats.ratings" by one, if the user inserts an input greater than 0, else increment zero.
"stats.answered" always increments one
See code below
module.exports.updateStats = function (req, res) {
var rating = parseInt(req.body.rating, 10);
var wasRated;
if (rating > 0) {
wasRated = true;
} else wasRated = false
Collection.findOneAndUpdate({
_id: req.body._id
}, {
$cond: {
if: wasRated,
then: {
$inc: {
"stats.answered": 1,
"stats.ratings": 1
}
},
else: {
$inc: {
"stats.answered": 1,
"stats.ratings": 0
}
}
}
},
function (err, doc) {
if (err)
throw err;
res.status(200);
})
}

What you can do is this:
// define the default case
var update = {
$inc: {
"stats.answered": 1
}
};
if(parseInt(req.body.rating, 10) > 0) {
// override default in some cases
update = {
$inc: {
"stats.answered": 1,
"stats.ratings": 1
}
}
}
and then
Collection.findOneAndUpdate({
_id: req.body._id
}, update,
function (err, doc) {
if (err)
throw err;
res.status(200);
})
}

Related

Remove object array items by comparing object array from mongodb

There is document which is having array of object inside.
Like
Objectid('')
fruits : [{_id:'2'},{_id:'3'},{_id:'4'}]
I want to delete these items fruits_id = [{_id:'3'},{_id:'4'}].
fruit_group.updateOne(
{collection_id: collection_id},
{$pullAll: {"fruits": fruits_id}}
)
so far i found below logic which i think is not efficient.
routes.post('/removeFruits', async (request, response, next) => {
var post_data = request.body;
var collection_id = post_data.collection_id;
var fruits_ids = JSON.parse(post_data.fruits_ids);
var prev_fruits;
await fruit_group.findOne({'collection_id': collection_id}, function (err, result) {
if (err) {
console("Some error occurred");
response.json({'message': "Some error occurred", 'result': 'false'});
}
prev_fruits = result.fruits;
});
for (var i = 0; i < fruits_ids.length; i++) { // this will delete all occurring items from array
var key = fruits_ids[i].user_id;
prev_fruits.filter(x => x.user_id === key).forEach(x => prev_fruits.splice(prev_fruits.indexOf(x), 1));
}
await fruit_group.updateOne({'collection_id': collection_id}, {$set: {'fruits': prev_fruits}}, function (err, result) {
if (err) {
response.json({'message': "Some error occurred", 'result': 'false'});
}
response.json({'message': 'Deletion successfully', 'result': 'true'});
});
});
is there anyway to achieve the same result?
Assuming fruits_id = [{ _id: '3' }, { _id: '4' }], you could do something like this using $pull and $in:
await fruit_group.updateOne({'collection_id': collection_id}, { $pull: { fruits: { $in: fruits_id }}})
This follows the example of removing all items that equal a specified value.

setInterval() is not wotking in azure microsoft

setInterval() is not working in Azure Microsoft. I need a function to do the task every month or week? so what can I do? the code is working without azure but with azure not working?
nodejs code :
setInterval(async function check() {
if ((date.getDate() == 8) && (date.getHours() == 18) && (date.getMinutes() == 39) && (date.getSeconds() == 00)) {
await Drawings.find({}).then((data) => {
data.sort(function (a, b) {
return b.stars - a.stars;
})
if (data == null) {
return;
}
AllDrawings.updateMany({
"potmCurrentWinner": true
}, {
$set: {
"potmCurrentWinner": false
}
}, async function (err) {
if (err) {
return;
}
// move the drawing to potm
await AllDrawings.updateOne({
"DrawingName": data[0]['DrawingName']
}, {
$set: {
"potmCurrentWinner": true,
"potm": true
}
}, async function (err) {
//move file
await User.updateOne({
userName: data[0].Drawer
}, {
$inc: {
stars: 25
}
})
console.log("done3");
await User.updateOne({
userName: data[0].Drawer
}, {
$inc: {
drawingOfTheMonth: 1
}
});
//delete all drawwing the u give star
await User.updateMany({}, {
$set: {
drawingThatGotYourStar: []
}
});
await Drawings.deleteMany({});
console.log("done4");
});
});
})
you have missing code here, the brackets from the initial condition and the closing parenthesis for the setInterval function call

can't use the results of a mongoose query when called from another function

I'm writing a blog engine using express, and ran into a problem when trying to run a mongoose query through a function:
What I'm trying to do is to obtain a variable that contains the next and previous blog posts by id, to do that I wrote this function:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {}
await Post.findOne({ _id: { $gt: _id } }).sort({ _id: 1 }).exec(async function(err, nextPost) {
if (err) {
console.log(err)
} else {
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
await Post.findOne({ _id: { $lt: _id } }).sort({ _id: -1 }).exec(
async function(err, previousPost) {
if (err) {
console.log(err.message);
} else {
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts)
return adjacentPosts
}
})
}
})
}
Before returning, I can see the variable completed with what I need through the console.log. The problem I have is that when I try to execute the function, the receiving variable is empty. This would be executed in the get route for a post, like the following:
Router.get("/posts/:slug", async function(req, res) {
await Post.findOne({ slug: req.params.slug }).populate('categories').populate('comments').exec(async function(err, foundBlog) {
if (err) {
console.log(err.message)
} else {
var posts = {}
posts = await middleware.getAdjacentPosts(foundBlog._id)
console.log(posts)
res.render("frontoffice/post", {
blog: foundBlog,
postUrl: req.params.slug,
adj: posts,
reCaptchaSiteKey: process.env.CAPTCHA_SITE_KEY
})
}
})
})
Any clues of what I might be doing wrong?
As #LucaKiebel suggests, you will need to return the results from your findOnes:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {};
return await Post.findOne({ _id: { $gt: _id } })
.sort({ _id: 1 })
.exec(async function(err, nextPost) {
if (err) {
console.log(err);
} else {
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
return await Post.findOne({ _id: { $lt: _id } })
.sort({ _id: -1 })
.exec(async function(err, previousPost) {
if (err) {
console.log(err.message);
} else {
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts);
return adjacentPosts;
}
});
}
});
};
A potential improvement, since you are using async/await anyway, might be to get rid of the callbacks:
middleware.getAdjacentPosts = async function(_id) {
var adjacentPosts = {};
try {
const nextPost = await Post.findOne({ _id: { $gt: _id } }).sort({ _id: 1 });
if (nextPost == null) {
adjacentPosts.nextPost = false;
} else {
adjacentPosts.nextPostUrl = nextPost.slug;
adjacentPosts.nextPostTitle = nextPost.title;
}
const previousPost = await Post.findOne({ _id: { $lt: _id } }).sort({ _id: -1 })
if (previousPost == null) {
adjacentPosts.previousPost = false;
} else {
adjacentPosts.previousPostUrl = previousPost.slug;
adjacentPosts.previousPostTitle = previousPost.title;
}
console.log(adjacentPosts);
return adjacentPosts;
} catch (err) {
console.log(err);
}
};
``

How to update records on continues Hierarchy in mongoose?

I have a record in such a way like below
1)
{
"name":"A",
"parents":[ADMIN],
"childrens":[B,C,D]
}
2)
{
"name":"B",
"parents":[A],
"childrens":[D,K,L]
}
3)
{
"name":"C",
"parents":[B],
"childrens":[K,L]
}
4)
{
"name":"D",
"parents":[C],
"childrens":[L]
}
Here if a add a new record 'E' and will make 'C' as parent ,then the logic is the record 'E' should be added as child to the parent of 'C'i.e for 'B' and at the same time 'E' should also be added to parent of 'B'.This logic is quite confusing when i start to write code and complex too but i achieved up to some extent that i can make 'E' as a child of 'C' and also the parent of 'C' but not further.
My Code:
function (callback) {
var item = {'employee' : employee.manager };
Employeehierarchy.find(item).exec(function (err, employeeparent) {
if (employeeparent && employeeparent.length > 0) {
Employeehierarchy.update(
{ _id: employeeparent[0]._id},
{"$push": { "childrens": employee._id } }
).exec(function (err, managerparent) {
});
callback(err,employeeparent);
} else{
callback(err,employeeparent);
}
}
});
},
//Finding the parent record of the manager in hierarchy
function (employeeparent, callback) {
var item = {'employee' : employeeparent[0].parents };
Employeehierarchy.find(item).exec(function (err, managerparent) {
if (err) {
return res.status(400).send({ message: errorHandler.getErrorMessage(err) });
} else {
if (managerparent && managerparent.length > 0) {console.log(managerparent+'managerparent')
Employeehierarchy.update(
{ _id: managerparent[0]._id},
{"$push": { "childrens": employee._id } }
).exec(function (err, managerparent) {
});
callback(err,managerparent);
} else{
callback(err,managerparent);
}
}
});
}else {
callback();
}

How can i have auto-increment field in nedb?

I want to have exactly auto-increment field like relational or objective databases, so i need an integer _id field with automatically set field value, value should be one more last record _id value like this:
data:
{_id:1,name"foo"}
{_id:2,name"bar"}
remove last record:
{_id:1,name"foo"}
add new record:
{_id:1,name"foo"}
{_id:3,name"newbar"}
I added a function to my datastore and calculate maximum of _id and plus 1 max(_id)+1 and set as field value, but there is problem here:
When we use auto-increment field in relational databases, it works like i said and after you remove last record it reserved a deleted record number and new inserted records continue increment but in my way its says the _id of removed record for new record.
My code is:
var Datastore = require('nedb'),
localDb = new Datastore({
filename: __dirname + '/dbFilePath.db',
autoload: true
});
localDb.getMax = function(fieldName, onFind){
db.find({}).sort({_id:-1}).limit(1).exec(function (err, docs) {onFind && onFind(err, docs['_id']);});
return localDb;
}
localDb.insertAutoId = function(data, onAdd){
var newIndex = 0;
localDb.getMax(function (err, maxValue) {
newIndex = maxValue+1;
if(!data["_id"])
data["_id"] = newIndex;
localDb.insert(data, function (err, newDoc) {
onAdd && onAdd(err, newDoc);
});
});
return localDb;
}
An improved answer for nedb would be:
db.getAutoincrementId = function (cb) {
this.update(
{ _id: '__autoid__' },
{ $inc: { seq: 1 } },
{ upsert: true, returnUpdatedDocs: true },
function (err, affected, autoid) {
cb && cb(err, autoid.seq);
}
);
return this;
};
Which is equivalent to the mongodb way:
db.getAutoincrementId = function (cb) {
this.findAndModify({
query: { _id: '__autoid__' },
update: { $inc: { seq: 1 } },
new: true
}
function (err, autoid) {
cb && cb(err, autoid.seq);
}
);
return this;
};
You can store the last value of the index in the database. Something like this:
var Datastore = require('nedb');
var db = new Datastore({
filename: __dirname + '/dbFilePath.db',
autoload: true
});
// Initialize the initial index value
// (if it already exists in the database, it is not overwritten)
db.insert({_id: '__autoid__', value: -1});
db.getAutoId = function(onFind) {
db.findOne( { _id: '__autoid__' }, function(err, doc) {
if (err) {
onFind && onFind(err)
} else {
// Update and returns the index value
db.update({ _id: '__autoid__'}, { $set: {value: ++doc.value} }, {},
function(err, count) {
onFind && onFind(err, doc.value);
});
}
});
return db;
}
I do not know if it will be useful for you anymore I use a database to store the next ids, inspired in the mysql system. Who always reserves the next id.
So I created a function that verifies if there is an id to the db, if it does not, it add with the value "1", and when it updates it looks for and if it exists and it performs the sequence.
This gave me full control over my ids.
The schema would be:
{
name: nameDb,
nextId: itemID
}
If you want you can create functions for updating documents, versioning, etc.
example:
db.autoincrement = new Datastore({filename: 'data/autoincrement.db', autoload: true});
function getUniqueId(nameDb, cb) {
db.autoincrement.findOne({name: nameDb}, function (err, doc) {
if (err) {
throw err;
} else {
if (doc) {
const itemID = doc.nextId + 1;
db.autoincrement.update({name: nameDb}, {
name: nameDb,
nextId: itemID
}, {}, function (err, numReplaced) {
db.autoincrement.persistence.compactDatafile();
if (err) {
throw err;
} else {
// console.log(numReplaced);
}
cb(doc.nextId);
});
} else {
const data = {
name: nameDb,
nextId: 2
};
db.autoincrement.insert(data, function (err, newDoc) {
if (err) {
throw err;
} else {
// console.log(newDoc);
}
cb(1);
});
}
}
});
}
insert new document example:
function insert(req, cb) {
getUniqueId("testdb", function (uniqueId) {
data.itemId = uniqueId;
db.testdb.insert(data, function (err, newDoc) {
if (err) {
cb({error: '1', message: 'error#2'});
throw err;
}
cb({error: '0', message: 'Item add'});
});
});
}

Resources