I have Error Called Arguments must be aggregate pipeline operators - node.js

I have some issues with MongoDB aggregate in node.js
Error: Arguments must be aggregate pipeline operators
This is my code
let find_result = await Users.aggregate([
{ $sample: { size: 10 } },
{ $group: { _id: '$_id'} },
{ $project: {
_id : {
$nin: arr2
}
}},
{ $unwind: '$_id' }
])
This code is to output randomly without duplication except for yourself and the person you choose (arr2 contains your _id and the _id of the person you choose)

Remove the comma before unwind.
let find_result = await Users.aggregate([
{ $sample: { size: 10 } }
,{ $group: { _id: '$_id'} },
{ $project: {
"_id" : {
$nin: arr2
}
}
},
{ $unwind: '$_id' },
])

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.

Can I use dynamic variable in $match mongoose

I want to filtre data using $match and group it using $group
since I use dynamic variable in $match stage I got no result,
let logs = await Promise.all(
tpes.map(async (item) => {
return await this.logModel.aggregate([
{ $match: { terminalId: item } },
{
$group: {
_id: '$outcome',
value: {
$sum: 1,
},
},
},
{
$project: {
name: '$_id',
value: 1,
_id: 0,
},
},
]);
}),
);
console.log('logs', logs);
logs here is an array contain ids from where I want to get data

how to group by in mongoose

Let's say I have a Collection with a field name and only "Sally" and "Bob" names exist. I want to group my results by this value. I'm currently getting my results and then using underscore to perform the group. But I should be able to do this with an aggregate.
The following is my code
const names = ['Bob', 'Sally'];
const docs = Collection.find({name: { $in: names}}, { fields: { name:1, age:1}, sort: { name:-1 } }).fetch();
//How can I do this part in the query above
const { Bob, Sally } = _.groupBy(docs, "name");
You can try,
$match your condition
$group by name and make array called fields and push name and age
$sort by _id means name
$replaceWith to replace object in root, $arrayToObject convert k, v format to object
const names = ['Bob', 'Sally'];
const docs = Collection.aggregate([
{ $match: { name: { $in: names } } },
{
$group: {
"_id": "$name",
fields: {
$push: {
name: "$name",
age: "$age"
}
}
}
},
{ $sort: { _id: -1 } },
{
$replaceWith: {
$arrayToObject: [
[
{
k: "$_id",
v: "$fields"
}
]
]
}
}
])
Playground
You can do something like this :
db.collection.aggregate([
{
$match: {
name: {
$in: names
}
}
},
{
$group: {
"_id": "$name",
age: {
$first: "$age"
}
}
},
{
$sort: {
name: -1
}
}
])
Try it here : MongoPlayground

Mongoose Aggregation not working, tried different ways still not able to solve the problem, even dont know what is problem

I am new to node and mongoose. Tried many ways though none worked for me.
Aggregate query on mongo shell is working, here is query:-
db.collection.aggregate([
{
$match: {
p_id: ObjectId("5d8b4f24d86d9f2400d7ff46"),
m_id: { $in: [ObjectId("5dde14b3f34ac02500a2b0aa")] }
}
},
{ $sort: { updated_at: 1 } },
{ $group: { _id: "$m_id", evaluation: { $last: "$evaluation" } } }
]);
Aggregate query in mongoose:-
Model.aggregate([
{ $match: { p_id: pId, m_id: { $in: mIds } } },
{ $sort: { updated_at: 1 } },
{
$group: {
_id: "$m_id",
evaluation: { $last: "$evaluation" }
}
}
]);
Error:- throwing cursor option is required
Aggregate query after adding cursor optionr:-
Query:-
Model.aggregate(
[
{ $match: { p_id: pId, m_id: { $in: mIds } } },
{ $sort: { updated_at: 1 } },
{
$group: {
_id: "$m_id",
evaluation: { $last: "$evaluation" }
}
}
],
{ cursor: {} }
);
Error: - error_stack=Error: Arguments must be aggregate pipeline operators
Mongoose aggregate api fluent returning aggregationcursor but on doing aggregationcursor.next() a promise is returned in pending state. After adding then() on aggregationcursor.next() a null object is returned:-
Model.aggregate()
.match({ p_id: pId, m_id: { $in: mIds } })
.sort({ $updated_at: 1 })
.group({
_id: "$m_id",
evaluation: { $last: "$evaluation" }
})
.cursor({ batchSize: 1000 });
Schema:
const PSchema = new Schema({
m_id: { type: Schema.Types.ObjectId },
p_id: { type: Schema.Types.ObjectId },
evaluation: { type: String, enum: _.values(EvaluationType) },
created_at: { type: Date },
updated_at: { type: Date }
});
Mongo/Mongoose version:-
"#types/mongoose": "^3.8.36",
"mongodb": "^3.3.5",
"mongoose": "~4.5.9",
I had to try different things, finally following query worked for me.
let cursor = Model.aggregate([
{
$match: {
'p_id': mongoose.Types.ObjectId(providerId) ,'m_id': { $in:objectIds }
}
},
{
$sort: {
'updated_at':1
}
},
{
$group: {
_id: '$m_id',
evaluation: { $last: '$evaluation' }
}
}
]).cursor({async:true});
Three things which i had to do:
I have to pass objectIds only in $match, as in normal find strings work, mongoose is able to convert strings into objectIds internally. For aggregate have to pass objectIds in $match.
Have to pass cursor option. As per [https://docs.mongodb.com/manual/reference/command/aggregate/#dbcmd.aggregate][1] cursor is mandatory after mongodb 3.6 version in aggregate. My mongodb version id 4.0.5 .
Had to pass cursor in async mode cursor({async:true}). Got results from cursor as cursor.toArray().

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
}
])

Resources