How to use mongoDB aggregartion in server side nodejs function? - node.js

I am new to nodejs, I am trying to get the all duplicate documents in a collection in mongoDB for that I have tried the following query in mongo shell
db.collection.aggregate([
{
$group: {
_id: {
ProductName: "$ProductName"
},
uniqueIds: {
$addToSet: "$_id"
},
count: {
$sum: 1
}
}
},
{
$match: {
count: {
$gte: 2
}
}
},
{
$sort: {
count: -1
}
}
])
In mongo shell result:
{
"_id" : {
"ProductName" : "Sony Mobile"
},
"uniqueIds" : [
ObjectId("5728ce42a069270e00e59910"),
ObjectId("5728cde6a069270e00e5990e")
],
"count" : 2
},
{
"_id" : {
"ProductName" : "Nokia Mobile"
},
"uniqueIds" : [
ObjectId("5728ce42a069270e00e59920"),
ObjectId("5728cde6a069270e00e5990f")
],
"count" : 2
}
In mongo shell it gaves the result what i want correctly, but i tried the same query in nodejs server side function like below
Company.aggregate([
{
$group: {
_id: {
Proname: "$Proname"
},
uniqueIds: {
$addToSet: "$_id"
},
count: {
$sum: 1
}
}
},
{
$match: {
count: {
$gte: 2
}
}
},
{
$sort: {
count: -1
}
}
]).then(function (dupProds) {
console.log("ALL DUPLICATE PRDCTS : " + JSON.stringify(dupProds));
})
};
It shows me an error that Compnay.aggregate(...).then is not a function, I tried in different ways but no use, now how can get the result same as like I got in mongoshell.

Use exec instead of then for mongoose and in callback function parameters error then result.
Company.aggregate([
{
$group: {
_id: {
Proname: "$Proname"
},
uniqueIds: {
$addToSet: "$_id"
},
count: {
$sum: 1
}
}
},
{
$match: {
count: {
$gte: 2
}
}
},
{
$sort: {
count: -1
}
}
]).exec(function (err,dupProds) {
if(err) {
// return err;
}
console.log("ALL DUPLICATE PRDCTS : ", dupProds);
// return dupProds
})
};
Actually then worked on promise so if you want to use then you need to promising. so can use like
aggregate([{..}]).exec().then(function(result){..})
where aggregate([{..}]).exec() return promise

You need call exec before then:
Company.aggregate(params).exec().then(function (dupProds) {
console.log("ALL DUPLICATE PRDCTS : " + JSON.stringify(dupProds));
})
};
[ http://mongoosejs.com/docs/api.html#aggregate_Aggregate-exec ]

Related

MongoServerError: PlanExecutor error during aggregation how to fix?

in the shopping cart project, am trying to get the total amount in the cart but my aggregation method has some problems , how to fix this ?
error
callback(new error_1.MongoServerError(document));
^
MongoServerError: PlanExecutor error during aggregation :: caused by :: Failed to parse number '1,39,999' in $convert with no onError value: Did not consume whole string.
user_helpers.js this the aggregation
getTotalAmount:(userId)=>{
return new Promise(async(resolve,reject)=>{
let total=await db.get().collection(collection.CART_COLLECTION).aggregate([
{
$match:{user:objectId(userId)}
},
{
$unwind:'$products'
},{
$project:{
item:'$products.item',
quantity:'$products.quantity',
}
},
{
$lookup:{
from:collection.PRODUCT_COLLECTION,
localField:'item',
foreignField:'_id',
as:'product'
}
},
{
$project:{
item:1,quantity:1,product:{$arrayElemAt:['$product',0]}
}
},
{
$group:{
_id:null,
total:{$sum:{$multiply:[{ $toInt: '$quantity'},{ $toInt: '$product.Price' }]}} // my assumption , here comes the error
}
}
]).toArray()
resolve(total.length > 0 ? total[0].total: 0) // or here
})
}
user.js
// GET: view shopping cart contents
router.get('/cart',middleware.verifyLogin,async(req,res,next)=>{
try{
let user=req.session.user._id;
let products =await userHelpers.getCartProducts(req.session.user._id)
let totalValue=0
if(products.length>0){
totalValue=await userHelpers.getTotalAmount(req.session.user._id)
let proId=req.params.id
console.log('proId>>>>>>>>>>',proId);
}
console.log('products>',products)
console.log("user...",user);
res.render('user/cart',{products,user,totalValue,});
}catch (error) {
console.log(error);
}
})
It comes when you click the cart button error is getting ,
how to fix this ?
The error message says itself, your database contains strings like 1,39,999. When MongoDB tries to convert these to an integer, it fails because of the commas. So, before converting the string to an integer, you should remove all the commas and other non-numeric characters from the string. Like this:
db.collection.aggregate([
{
$match: {
user: ObjectId("userId433456666666666666")
}
},
{
$unwind: "$products"
},
{
$project: {
item: "$products.item",
quantity: "$products.quantity",
}
},
{
$lookup: {
from: "collection.PRODUCT_COLLECTION",
localField: "item",
foreignField: "_id",
as: "product"
}
},
{
$project: {
item: 1,
quantity: 1,
product: {
$arrayElemAt: [
"$product",
0
]
}
}
},
{
$group: {
_id: null,
total: {
$sum: {
$multiply: [
{
$toInt: '$quantity'
},
{
$toInt: {
"$replaceAll": {
"input": "$product.Price",
"find": ",",
"replacement": ""
}
}
}
]
}
}
}
}
]).toArray()
Here we are using $replaceAll to replace the commas with an empty string.

MongoDB Aggregation: How to get both group _id and total records count?

I'm working with a MongoDB collection that has a lot of duplicate keys. I regularly do aggregation queries to find out what those duplicates are, so that I can dig in and find out what is and isn't different about them.
Unfortunately the database is huge and duplicates are often intentional. What I'd like to do is to find the count of keys that have duplicates, instead of printing a result with thousands of lines of output. Is this possible?
(Side Note: I do all of my querying through the shell, so solutions that don't require external tools or a lot of code would be preferred, but I understand that's not always possible.)
Example Records:
[
ObjectId("622f2d94ecf6a5076c2e230b"),
ObjectId("622f329c6f10fe0490252611"),
ObjectId("623026366f10fe0490254341"),
ObjectId("623026de6f10fe0490254583"),
ObjectId("6234346adec0b842dcceb790"),
ObjectId("623434a86f10fe0490260db6"),
ObjectId("62382f91dab1e245d4e152f4"),
ObjectId("6238303b6f10fe0490265acf"),
ObjectId("623bf2af700224301c756394"),
ObjectId("623bf2f76f10fe04902729a4"),
ObjectId("623c5a1f282a052c3c0bbdfd"),
ObjectId("624bf013383df47699e6b141")
]
Here is the query that I've been using to find duplicates based on key:
db.getCollection('weldtestings').aggregate([
{
$match: {
weldId: {
$in: [
ObjectId("622f2d94ecf6a5076c2e230b"),
ObjectId("622f329c6f10fe0490252611"),
ObjectId("623026366f10fe0490254341"),
ObjectId("623026de6f10fe0490254583"),
ObjectId("6234346adec0b842dcceb790"),
ObjectId("623434a86f10fe0490260db6"),
ObjectId("62382f91dab1e245d4e152f4"),
ObjectId("6238303b6f10fe0490265acf"),
ObjectId("623bf2af700224301c756394"),
ObjectId("623bf2f76f10fe04902729a4"),
ObjectId("623c5a1f282a052c3c0bbdfd"),
ObjectId("624bf013383df47699e6b141")]
}
}
},
{
$facet: {
"NDEfailedDate": [
{
$match: { testResult: 'Failed' }
},
{
$group: {
_id: { $dateToString: { format: "%Y-%m-%d", date: "$testDate" } },
count: { $sum : 1 }
}
},
{ $sort: { _id: 1 } }
],
"NDEfailedCount": [
{
$match: { testResult: 'Failed' }
},
{
$group: {
_id: "$weldId",
data: { "$addToSet": "$testDate" }
}
},
{ $count: "totalCount" }
],
}
}
])
Which gives me an output of:
{
"NDEfailedDate" : [
{
"_id" : "2022-04-08",
"count" : 6.0
}
],
"NDEfailedCount" : [
{
"totalCount" : 5
}
]
}
The result I want to get instead:
"_id" : "2022-04-08",
"count" : 5
db.collection.aggregate([
{
$project: {
_id: {
$first: "$NDEfailedDate._id"
},
count: {
$first: "$NDEfailedCount.totalCount"
}
}
}
])
mongoplayground

How to find the latest date in nested array of objects (MongoDB)

I am trying to find the latest "order" in "orders" array in the whole collection (Not only in the one object).
Data:
[
{
_id: 1,
orders: [
{
title: 'Burger',
date: {
$date: '2021-07-18T13:12:08.717Z',
},
},
],
},
{
_id: 2,
orders: [
{
title: 'Salad',
date: {
$date: '2021-07-18T13:35:01.586Z',
},
},
],
},
];
Code:
var restaurant = await Restaurant.findOne({
'orders.date': 1,
});
Rather simple:
db.collection.aggregate([
{ $project: { latest_order: { $max: "$orders.date" } } }
])
If you like to get the full order use this:
db.collection.aggregate([
{
$project: {
latest_order: {
$first: {
$filter: {
input: "$orders",
cond: { $eq: [ "$$this.date", { $max: "$orders.date" } ] }
}
}
}
}
},
{ $sort: { "latest_order.date": 1 } },
{ $limit: 1 }
])
Mongo Playground
You have to use aggregation for that
db.collection.aggregate([
{ $unwind: "$orders" },
{ $sort: { "orders.date": -1 } },
{ $limit: 1 },
{
"$group": {
"_id": "$_id",
"orders": { "$first": "$orders" }
}
}
])
Working Mongo playground

Aggregate and Sort Documents based on array element date time and field

Currently I have the following schema:
User:{
verified:boolean,
history:[{
type:string,
dateTime:datetime
}]
}
I need to aggregate and sort the data based on the history.type and history.datetime. For example, I have 100 documents. Half of it have history.type="Testing" and each of the history have its own datetime.
I need to match the history type and sort the datetime using mongoose nodejs.
Here is what I did but didn't work as expected:
let user = await User.aggregate([
{
$match: {
"nameVerified":true,
'history.type' : 'NAME_VERIFIED'
}
},
{$unwind: '$history'},
{
$match: {
'history.type' : 'NAME_VERIFIED'
}
},
{
$group : {
_id :'$_id'
}
},
{
$sort:
{
'history.dateTime': -1
}
}]);
Sample Data:
{_id:1,verified:false,history:[...]}
{_id:2,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-23},{type:"TEST",dateTime:2018-10-25}]}
{_id:3,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-24},{type:"TEST",dateTime:2018-10-21}]}
{_id:4,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-21},{type:"TEST",dateTime:2018-10-21}]}
{_id:5,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-22},{type:"TEST",dateTime:2018-10-21}]}
Expected results:
{_id:3,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-24},{type:"TEST",dateTime:2018-10-21}]}
{_id:2,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-23},{type:"TEST",dateTime:2018-10-25}]}
{_id:5,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-22},{type:"TEST",dateTime:2018-10-21}]}
{_id:4,verified:true,history:[{type:"NAME_VERIFIED",dateTime:2018-10-21},{type:"TEST",dateTime:2018-10-21}]}
Anyone can suggest a solution?
The following query will return array of documents with matching history.type and sorted by history.dateTime.
User.aggregate([{
$match: {
"history.type": 'NAME_VERIFIED',
}
},
{
$unwind: '$history'
},
{
$match: {
"history.type": 'NAME_VERIFIED',
}
},
{
$sort: {
'history.dateTime': -1
}
},
{
$group: {
'_id': {
'_id': '$_id',
'verified': '$verified'
},
'history': {
'$push': '$history'
}
}
},
{
$project: {
'_id': '$_id._id',
'verified': '$_id.verified',
'history': 1
}
}
])
If anything should be changed in criteria, please let me know, I will try to reshape the query.
Finally I found a solution as follow:
User.aggregate([
{
$match: {
"nameVerified":true,
"history.type": 'NAME_VERIFIED',
}
},
{
$unwind: '$history'
},
{
$match: {
"nameVerified":true,
"history.type": 'NAME_VERIFIED',
}
},
{
$sort: {
'history.dateTime': -1
}
},
{
$group: {
_id: '$_id',
'history': {
'$push': '$history'
}
}
},
{
$sort: {
'history.dateTime': -1
}
},
{
$skip: skipNo
},
{
$limit: limitNo
}
])

Query with variables not working using nodejs ,express, mongojs and mongodb

My application needs to get the result of this query (this is already giving the correct result in mongoDb):
var denominator = db.getCollection('Transactions').aggregate({
$group: {
"_id": null,
"Alltotal": {$sum:"$transAmount"}
}
};
db.getCollection('Transactions').aggregate([{
$group: {
_id: '$merchantCode',
total: {
$sum: { $multiply: ['$transAmount', 100 ]}
}}},
{ $project: {
percentage: {
$divide: [
"$total",
denominator.toArray()[0].Alltotal
]
}
}
}
])
Now here is how I am trying to execute it:
var express = require('express');
var app = express();
var mongojs = require('mongojs');
var dbTransaction = mongojs('dataAnalysisDb',['Transactions']);
app.get('/Transactions',function(req,res){
var denominator = dbTransaction.Transactions.aggregate([{
$group: {
_id: 'null',
total: { $sum: '$transAmount' }
}
}]);
dbTransaction.Transactions.aggregate([{
$group: {
_id: '$mtype',
total: {
$sum: { $multiply: ['$transAmount', 100 ]}
}}},
{ $project: {
percentage: {
$divide: [
"$total",
denominator.toArray()[0].total
]
}
}
},
{ $sort : { _id : 1, posts: 1 } }
], function(err,docs){
console.log(docs); //this is for testing
res.json(docs);
});
});
I think this is not working because I am not sending the variable in the correct way to the server and when I use it on the operation it is not defined. I will appreciate any suggestion on how to fix it.
Thank you
I found a way to solve it and it might not be the best but it worked, I leave it here for whoever else needs it
var denominator = dbTransaction.Transactions.aggregate([{
$group: {
"_id": null,
"Alltotal": {$sum:"$transAmount"}
}}]).toArray(function(err,items){
console.log(items[0].Alltotal); //this is for testiong
dbTransaction.Transactions.aggregate([{
$group: {
_id: '$mtype',
total: {
$sum: { $multiply: ['$transAmount', 100 ]}
}}},
{ $project: {
percentage: {
$divide: [
"$total",
items[0].Alltotal
]
}
}
},
{ $sort : { _id : 1, posts: 1 } }
],function(err,docs){
console.log(docs); //this is for testing
res.json(docs);
});
});

Resources