Mongodb javascript variable - javascript

I need to use the string value in nodejs in a mongo query. But on passing those variable in [] I get back an undefined object. Putting the actual value however does give the right answer
var myquery = [
{
$match: {
time: {
$gte: [start_time],
$lt: [end_time]
},
payeeFsp : [dfsp_given]
}
},
{
$group: {
_id: null,
total: {$sum:"$amount"}
}
}
];
dbo.collection("transaction_history").aggregate(myquery).toArray(function(err, res) {
if (err) throw err;
console.log(res);
db.close();
});

Why would you put the variables in array?
I think the query should be like this
var myquery = [
{
$match: {
time: {
$gte: start_time,
$lt: end_time
},
payeeFsp : dfsp_given
}
},
{
$group: {
_id: null,
total: {$sum:"$amount"}
}
}
];

Related

Use mongoDB $lookup to find documents in another collection not present inside an array

I'm using the aggregate framework to query a collection and create an array of active players (up until the last $lookup) after which I'm trying to use $lookup and $pipeline to select all the players from another collection (users) that are not present inside the activeUsers array.
Is there any way of doing this with my current setup?
Game.aggregate[{
$match: {
date: {
$gte: ISODate('2021-04-10T00:00:00.355Z')
},
gameStatus: 'played'
}
}, {
$unwind: {
path: '$players',
preserveNullAndEmptyArrays: false
}
}, {
$group: {
_id: '$players'
}
}, {
$group: {
_id: null,
activeUsers: {
$push: '$_id'
}
}
}, {
$project: {
activeUsers: true,
_id: false
}
}, {
$lookup: {
from: 'users',
'let': {
active: '$activeUsers'
},
pipeline: [{
$match: {
deactivated: false,
// The rest of the query works fine but here I would like to
// select only the elements that *aren't* inside
// the array (instead of the ones that *are* inside)
// but if I use '$nin' here mongoDB throws
// an 'unrecognized' error
$expr: {
$in: [
'$_id',
'$$active'
]
}
}
},
{
$project: {
_id: 1
}
}
],
as: 'users'
}
}]
Thanks
For negative condition use $not before $in operator,
{ $expr: { $not: { $in: ['$_id', '$$active'] } } }

Running sequelize with two where conditions

I have a mysql db instance with a table consisting of a various fields. Relevant fields are start, start time, and status
start: YYYY-MM-DD
startTime: HH:mm:ss
status: ENUM('cancelled', 'scheduled, etc)
If I want to get a list of all entries that don't have status = 'cancelled' and that occur today or after, I would write this:
return {
where: {
status: {
$ne: 'cancelled'
},
$or: {
start: { $gte: moment().utc().format('YYYY-MM-DD') },
$and: {
isRepeating: 1,
$or: [{
end: {
$gte: moment().format(),
}
},
{
end: {
$eq: null,
}
}]
},
}
},
I am trying to modify this query to not only give me entries that occur today or after, but also greater than right now (time wise, UTC). My attempt was to first filter based on startTime, and then filter based on startDate, but it does not seem to be working:
return {
where: {
status: {
$ne: 'cancelled'
},
$or: {
startTime: { $gt: moment.utc().format('HH:mm:ss') },
$and: {
start: { $gte: moment().utc().format('YYYY-MM-DD') },
$and: {
isRepeating: 1,
$or: [{
end: {
$gte: moment().format(),
}
},
{
end: {
$eq: null,
}
}]
}
},
}
},
(does not work, because it just returns everything!)
I also cannot do something more simple like
where: {
startTime: { $gt: moment.utc().format('HH:mm:ss') },
start: { $gte: moment().utc().format('YYYY-MM-DD') },
}
Because then it will ignore, for example, entries that occur tomorrow date wise, but occur earlier in the day than the current timestamp.
Thanks!
You can use Op.and operator to combine those conditions.
const { Op } = require("sequelize");
...
where: {
[Op.and]: [
startTime: { $gt: moment.utc().format('HH:mm:ss') },
start: { $gte: moment().utc().format('YYYY-MM-DD') }
]
}
...

How to use group by and sum in Mongoose?

I have a JSON array that contains objects like this one
{
"InvoiceNo": "FA 2019/1",
"Period": "01",
"DocumentTotals": {
"TaxPayable": "26.94",
"NetTotal": "117.16",
"GrossTotal": "144.10"
},
"WithholdingTax": {
"WithholdingTaxAmount": "0.00"
}
},
I want to sum the GrossTotal of the various objects and group it by Period.
I tried with the following code:
saftFileController.revenuePerMonth = function (req, res) {
Saft.find().exec(function (err, fileContent) {
if (err) {
console.log(err);
} else {
const JSONObject = JSON.parse(JSON.stringify(fileContent));
const sales = JSONObject[3].SalesInvoices.Invoice;
const revenuePerMonth = Saft.aggregate([
{
$group: {
Period: sales.Period,
revenue: {
$sum: "$GrossTotal",
},
},
},
]);
res.json({ revenue: revenuePerMonth });
}
});
};
But the output wasn´t the desired one. What I am doing wrong? This was the output:
{
"revenue": {
"_pipeline": [
{
"$group": {
"revenue": {
"$sum": "$GrossTotal"
}
}
}
],
"options": {}
}
}
Here are some printscreens of my Database
https://snipboard.io/QOfiYz.jpg
https://snipboard.io/72LSRC.jpg
Did this and now returns the Period but it is ignoring the sum because it is a string type.How can I convert?
saftFileController.revenuePerMonth = function (req, res) {
Saft.aggregate([
{
$group: {
_id: "$SalesInvoices.Invoice.Period",
revenue: {
$sum: "SalesInvoices.Invoice.DocumentTotals.GrossTotal",
},
},
},
]).exec(function (err, fileContent) {
if (err) {
console.log("Error: ", error);
} else {
res.json({ revenuePerMonth: fileContent });
}
});
};
You should pass the MongoDB expression what you want to group it by as _id in the $group stage (documentation). The $sum expression should contain the full path as well.
$group: {
_id: '$Period',
revenue: {
$sum: "$DocumentTotals.GrossTotal",
},
},
aggregate accepts a callback, or returns a Promise just like when you use Saft.find()
Saft.aggregate([/* ... */]).exec(function (err, result) {
/* use result here */
})

Mongoose $slice and get orginal size array

I'm currently trying to get the total amount of items in my News object, and return a slice of the items as objects.
I found out how to use the $slice operator in my query, but I don't know how to get the original size of the array of items.
The code I'm currently using in NodeJS:
if (req.query.limit) {
limit = 5;
}
News.findOne({ connected: club._id }, {items: {$slice: limit}}).exec(function (err, news) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else if (!news || news.items.length === 0) {
res.jsonp([]);
} else {
const returnObj = { items: [], totalNumber: 0 };
const items = news.items.sort(function (a, b) {
return b.date - a.date
});
res.jsonp({
items: items,
totalNumber: news.items.length
});
}
});
The Mongo model:
var mongoose = require('mongoose'),
validator = require('validator'),
Schema = mongoose.Schema;
var NewsSchema = new Schema({
connected: {
type: Schema.Types.ObjectId,
required: 'Gelieve een club toe te wijzen.',
ref: 'Club'
},
items: [{
userFirstName: String,
action: String,
date: Date,
targetName: String
}],
created: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('News', NewsSchema);
How would I do this efficiently?
Thanks!
EDIT: final code which works:
News.aggregate([{
$match: {
connected: club._id
}
}, {
$project: {
totalNumber: {
$size: '$items'
},
items: {
$slice: ['$items', limit]
}
}
}
]).exec(function (err, news) {
console.log(news);
if (!news || news[0].items.length === 0) {
res.jsonp([]);
} else {
res.jsonp(news[0]);
}
});
You cannot have both information at once using find and $slice.
The soluce you have :
Use aggregate to return the count and only the sliced values.
Like :
[{
$project: {
count: {
$size: "$params",
},
params: {
$slice: ["$params", 5],
},
},
}]
To help you out making aggregate, you can use the awesome mongodb-compass software and its aggregate utility tool.
Use a find without $slice, get the number of item there, and then slice in javascript the array before returning it.
EDIT :
[{
$sort: {
'items.date': -1,
},
}, {
$project: {
count: {
$size: "$items",
},
params: {
$slice: ["$items", 5],
},
},
}]

(mongoDB) find with empty or null values

how to make a mongodb collection find (db.collection.find) with empty values?
currently i have:
function test(s) {
if (!s) {
return null;
} else {
return s;
}
}
var content = {
date: {
from: '2017-10-15',
to: '2017-11-15'
},
'name': 'some text', //this can be null or empty
'text': 'some other text' //this can be null or empty
}
col.find({
"date": {
$gte: new Date(content.date.from),
$lte: new Date(content.date.to)
},
"name": {
$ne: {
$type: null
},
$eq: test(content.name)
},
"text": {
$ne: {
$type: null
},
$eq: test(content.text)
},
}).toArray((err, items) => {
console.log(items)
});
but it returns an empty array, because "name" or "text" is null / an empty string,
i want that it query only the values that have something specified or ignore it (like content.name is something in it or its empty)
how do i get it? i already searched ... but didnt found something
thanks!
( already testet mongoDB : multi value field search ignoring null fields)
Versions:
Node: 8.9.0
(npm) mongodb: 2.2.33
mongodb: 3.4
Try using $and, $or operators. Something like.
col.find({
$and:[
{"date": {$gte: new Date(content.date.from),$lte: new Date(content.date.to)}},
{"$or":[{"name": {$ne: {$type: null}}},{"name":test(content.name)}]},
{"$or":[{"text": {$ne: {$type: null}}},{"text":test(content.text)}]}
]
}).toArray((err, items) => {
console.log(items)
});
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': content.text }
]
}
]
})
Edited:
col.find({
$and: [
{
$and: [
{
"date": {
$gte: new Date(content.date.from)
}
},
{
"date": {
$lte: new Date(content.date.to)
}
},
]
},
{
$or: [
{ 'name': null },
{ 'name':'' }
{ 'name': content.name }
]
},
{
$or: [
{ 'text': null },
{ 'text': '' },
{ 'text': content.text }
]
}
]
})
null and empty is different, you need to add one more condition for empty string in query.
Logical Query Operators

Categories

Resources