Conditional $sum query in mongoDB - node.js

I want to get sum of filed reqAmount in my mongodb database of a particular user.
Here is the schema
const userid = req.body.userId;
const id = mongoose.Types.ObjectId(userid);
fundReq.aggregate([
{ $match : { userId : id } },
{
$group: {
_id : '',
total: {$sum : "$reqAmount"}
}
}
],function (err, result) {
if (err) throw err;
else res.json(result);
})
but getting null in result...

it's Working Fine For You
const ObjectId = require('mongodb').ObjectId;
function fnGetTotalCollectionAmount(callback) {
TransactionModel.aggregate([
{
$match: { '_id': ObjectId(productId) }
},
{
$group: {
_id: null,
grandTotal: {
$sum: '$subTotal'
}
}
}
]).exec(function (err, transaction) {
if (err) {
return callback(err);
} else {
return callback(transaction[0].grandTotal);
}
});
}

Related

How to project a new boolean field in Mongoose if another property is listed in existing array?

Consider the query in Mongoose :
let StudentCodes = .... // getting this from somewhere
await Students.aggregate(
[
{
$project: {
StudentCODE: "$StudentCODE",
StudName: "$StudName",
StudProfileDesc: "$StudProfileDesc",
IsReviewed: {
$cond: [{ $eq: [StudentCodes, "$StudentCODE"] }, 1, 0]
}
}
}
],
function(err, results) {
if (err) {
console.log(err);
}
console.log(results);
return res.status(200).json(results);
}
);
How can We project IsReviewed as true or false if the property StudentCODE exists in the array StudentCodes ?
Try as below, you can use $in in $cond to do that :
let StudentCodes = .... // getting this from somewhere
await Students.aggregate(
[
{
$project: {
StudentCODE: "$StudentCODE",
StudName: "$StudName",
StudProfileDesc: "$StudProfileDesc",
IsReviewed: {
$cond: [{ $in: ["$StudentCODE", StudentCodes] }, true, false]
}
}
}
],
function (err, results) {
if (err) {
console.log(err);
}
console.log(results);
return res.status(200).json(results);
}
);

Nodejs + Mongodb: find data after aggregation

I'm a new to Nodejs and MongoDB.
Here is a sample of my dataset:
{
'name': ABC,
'age':24,
'gender':male,
...
}
Generally speaking, what I want to do is to aggregate data before using them to find different data clusters.
To be specific, I want to know how many people there are at different ages. Then, to find people(documents) at each age and store them.
Here is my code:
MongoClient.connect(url, function(err, db) {
if(err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
db.collection('test').aggregate(
[
{ $group: { _id: "$age" , total: { $sum: 1 } } },
{ $sort: { total: -1 } }
]).toArray(function(err, result) {
assert.equal(err, null);
age = [];
for(var i in result) {
age.push(result[i]['_id'])
};
ageNodes = {};
for(var i in age) {
nodes = [];
var cursor = db.collection('test').find({'age':age[i]});
// query based on aggregated data
cursor.each(function(err,doc){
if(doc!=null){
nodes.push(doc);
} else {
console.log(age[i]);
ageNodes[age[i]] = nodes;
}
})
}
res.json(ageNodes);
});
};
});
My expected JSON format:
{
age:[different documents]
}
example:
{
20:[{name:A,gender:male,...},{},...],
30:[{name:B,gender:male,...},{},...],
...
}
However, what I got was an empty result, so I think maybe it was caused by the for loop.
I have no idea how to handle the asynchronous callback.
You only need to run the following pipeline which uses $push to add the root document (represented by $$ROOT system variable in the pipeline) to an array per age group:
Using MongoDB 3.4.4 and newer:
MongoClient.connect(url, function(err, db) {
if(err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
db.collection('test').aggregate([
{ '$group': {
'_id': '$age',
'total': { '$sum': 1 },
'docs': { '$push': '$$ROOT' }
} },
{ '$sort': { 'total': -1 } },
{ '$group': {
'_id': null,
'data': {
'$push': {
'k': '$_id',
'v': '$docs'
}
}
} },
{ '$replaceRoot': {
'newRoot': { '$arrayToObject': '$data' }
} }
]).toArray(function(err, results) {
console.log(results);
res.json(results);
});
};
});
Using MongoDB 3.2 and below:
MongoClient.connect(url, function(err, db) {
if(err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
db.collection('test').aggregate([
{ '$group': {
'_id': '$age',
'total': { '$sum': 1 },
'docs': { '$push': '$$ROOT' }
} },
{ '$sort': { 'total': -1 } }
]).toArray(function(err, results) {
console.log(results);
var ageNodes = results.reduce(function(obj, doc) {
obj[doc._id] = doc.docs
return obj;
}, {});
console.log(ageNodes);
res.json(ageNodes);
});
};
});

Node.js "ignore" $sort in a collection.aggregate query

This could be a dumb question, but I'm desperate already! I need to do this query:
db.clients.aggregate(
{
$group: {
_id: '$enterprise',
lodging_days: { $sum: '$lodging_days' }
}
},
{
$sort : {
lodging_days: -1
}
})
And, if I copy this on the mongo bash, I returned this: Bash Return
(Sorry, I can't upload images yet)
JUST LIKE I WANT!
But, when I put the query on node:
router.get('/query', function(req, res){
var db = req.db;
var clients=db.get('clients');
clients.aggregate(
{
$group: {
_id: '$enterprise',
lodging_days: { $sum: '$lodging_days' }
}
},
{
$sort: {
'lodging_days': -1
}
},
function(e, data){
res.json(data);
}
);
});
This "ignore" the $sort and return me this: Interface Return
Now, my question are... Why!? And what can I make to fix it?
Your need to wrap your pipeline into array.
router.get('/query', function(req, res){
var db = req.db;
var clients=db.get('clients');
clients.aggregate([
{
$group: {
_id: '$enterprise',
lodging_days: { $sum: '$lodging_days' }
}
},
{
$sort: {
'lodging_days': -1
}
}],
function(e, data){
res.json(data);
}
);
});

group on mongodb filtering by any field

I am trying to make a group query on mongodb (using mongoose) filtering by any other different field than the group criteria. I have this by the moment:
usersDB.aggregate().group (
{_id: '$residence', total: { $sum: 1 } }
).exec(function (err, result) {
if(err) res.send(err);
else res.send(result);
});
And it works... it shows me for example:
[{"_id":"Javea","total":40},{"_id":"Benissa","total":28},{"_id":"Calpe","total":41},{"_id":"Teulada","total":14}]
But now, what I want to do is filtering too by date of last visit (last_visit is other field of UsersDB). I tried this:
usersDB.find({$and:[{last_visit:{$lt:date}}, {last_visit:{$gt:date.setMonth(3)}}]}).aggregate().group(
{_id: '$residence', total: { $sum: 1 } }).exec(
function (err, result) {
if(err) res.send(err);
else res.send(result);
});
And of course... it doesn't work!!
Any suggestion?
You need to do the filtering within the aggregation pipeline using the $match operator stage:
var start = date, end = date;
end.setMonth(3);
var query = { "last_visit": { "$lt": end, "$gt": start } };
usersDB.aggregate()
.match(query)
.group({"_id": "$residence", "total": { "$sum": 1 } })
.exec(function (err, result) {
if(err) res.send(err);
else res.send(result);
});
in mongo shell, it look's like:
db.users.aggregate([
{ $match : { $and [{last_visit:{$lt:date}}, {last_visit:{$gt:date.setMonth(3)}}]}},
{ $group : { _id: '$residence', total: { $sum: 1 } }}
]);

What am I doing wrong trying to make this run with meteor?

I am trying to adapt the full text search made here to work with meteor. I exported the mongodb url to one running 2.6.1. to make full text search compatible but I am getting these errors server/search.js:2:15: Unexpected token .andserver/search.js:42:7: Unexpected token ). What am I missing?
server.js
Meteor.methods({
Meteor.ensureIndex("Posts", {
smaintext: "text"
}, function(err, indexname) {
assert.equal(null, err);
});
)
};
Meteor.methods({
feedupdate: function(req) {
Posts.find({
"$text": {
"$search": req
}
}, {
smaintext: 1,
submitted: 1,
_id: 1,
Posts: {
$meta: "Posts"
}
}, {
sort: {
textScore: {
$meta: "posts"
}
}
}).toArray(function(err, items) {
for (e=0;e<101;e++) {
Meteor.users.update({
"_id": this.userId
}, {
"$addToSet": {
"profile.search": item[e]._id
}
});
}
})
}
)
};
This is wrong definition of method
Meteor.methods({
Meteor.ensureIndex("Posts", {
smaintext: "text"
}, function(err, indexname) {
assert.equal(null, err);
});
)
};
you must specify a method name ( http://docs.meteor.com/#/basic/Meteor-methods )
So it will be something like this
Meteor.methods({
myMethodName : function() { Meteor.ensureIndex("Posts", {
smaintext: "text"
}, function(err, indexname) {
assert.equal(null, err);
});
}
});
in second method there is a semicron and parenthise problem.
Correct version is
Meteor.methods({
feedupdate: function(req) {
Posts.find({
"$text": {
"$search": req
}
}, {
smaintext: 1,
submitted: 1,
_id: 1,
Posts: {
$meta: "Posts"
}
}, {
sort: {
textScore: {
$meta: "posts"
}
}
}).toArray(function(err, items) {
for (e=0;e<101;e++) {
Meteor.users.update({
"_id": this.userId
}, {
"$addToSet": {
"profile.search": item[e]._id
}
});
}
});
}
});

Resources