NodeJS MongoDB Pass parameter in the aggregation pipeline - node.js

How to pass an parameter to the aggregation?
I'm getting the params and trying to pass it using $match operator but query returns empty array:
app.get('/api/:name', function(req, res){
var name = req.params.name;
console.log(name);
db.collection('coll').aggregate([{$match: {name: '$name'}}, {$unwind: { path: "$dates", includeArrayIndex: "idx" } }, { $project: { _id: 0, dates: 1, numbers: { $arrayElemAt: ["$numbers", "$idx"] }, goals: { $arrayElemAt: ["$goals", "$idx"] }, durations: { $arrayElemAt: ["$durations", "$idx"]}}}]).toArray(function(err, docs) {
if (err) {
assert.equal(null);
}
else {
console.log(docs);
res.json(docs);
}
});
})
Should I care about order of the operators in pipeline?

Try the following code:-
app.get('/api/:name', function(req, res){
var name = req.params.name;
var query = [{$match: {'name': name}}, {$unwind: { path: "$dates", includeArrayIndex: "idx" } }, { $project: { _id: 0, dates: 1, numbers: { $arrayElemAt: ["$numbers", "$idx"] }, goals: { $arrayElemAt: ["$goals", "$idx"] }, durations: { $arrayElemAt: ["$durations", "$idx"]}}}];
db.collection('coll').aggregate(query).toArray(function(err, docs) {
if (err) {
assert.equal(null);
}
else {
console.log(docs);
res.json(docs);
}
});
})

It seems you never use variable called name.
Try this, change {$match: {name: '$name'} to {$match: {name: name}.

try,
{$match: {'name': req.params.name}}
this works for me

Mongoose does not cast pipeline stages. The below will not work unless _id is a string in the database
new Aggregate([{ $match: { _id: '00000000000000000000000a' } }]);
// Do this instead to cast to an ObjectId
new Aggregate([{ $match: { _id:
mongoose.Types.ObjectId('00000000000000000000000a') } }]);
API URL: https://mongoosejs.com/docs/api.html#aggregate_Aggregate

Related

I have an error about mongoose Error: Arguments must be aggregate pipeline operators

Hi I'm new to the mongoose I got an error that Error: Arguments must be aggregate pipeline operators this
I just try to get posts from users who I'm following
I have no idea to solve this problem. It's my first time using aggregate function
here's my code
export const getPosts = async (req, res) => {
const user = req.user;
console.log(user);
try {
if (user.following.length === 0) return res.json("No following users");
//user.following = string[]
const followingPosts = await Post.aggregate([
{
$match: {
userId: { $in: user.following },
},
$sort: {
createdAt: 1,
},
$limit: 10,
},
]);
res.status(200).json(followingPosts);
} catch (error) {
console.log(error);
res.status(404).json({ message: error.message });
}
};
is there a good way to solve this problem let me know
I'd really appreciate it. thanks for reading my qeustion
Your query is syntactically wrong, you are creating one single object for different stages, and mongo expects each stage to be a separate object.
const followingPosts = await Post.aggregate([
{
$match: {
userId: { $in: user.following },
},
$sort: {
createdAt: 1,
},
$limit: 10,
},
]);
The above syntax is wrong. Try this:
const followingPosts = await Post.aggregate([
{
$match: {
userId: { $in: user.following },
}
},
{
$sort: {
createdAt: 1,
},
},
{
$limit: 10,
},
]);

Pull element from an array of arrays MongoDb

I am struggling to find the format for a query to remove an element (with an _id) from an array of arrays in Mongo.
When looking at the docs I couldn't find anything that was similar to what I have
https://www.mongodb.com/docs/manual/reference/operator/update/pull/#up._S_pull
I know: the _id of the document in MySchema and the _id of the array element in innerArray.
I don't know the outerArray _id
Could someone help point out where I went wrong Thank you!
This is an example of the data (imagine the _id in ObjectId)
{
outerArray:[
{
_id: 1
innerArray: [{_id: 23, name: '123'}, {_id: 13, name: 'asdac'} ]
},
{
_id: 2,
innerArray: [{_id: 16,name:'asf' }, {_id: 18,name:'asf' } ]
},
{
_id: 3,
innerArray: [{_id: 136,name:'asf' }, {_id: 128,name:'asf' } ]
}
]
}
innerIds is an array of mongoose.Types.ObjectId
return MySchema.updateOne(
{
_id: documentId,
},
{ $pull: { outerArray: { innerArray: { _id: { $in: innerIds } } } } },
)
.session(session)
.exec()
db.collection.update({},
{
$pull: {
"outerArray.$[].innerArray": {//$[] does the trick
_id: {
$in: [
16
]
}
}
}
})
playground

MongoDB how to update array of objects with id and updated values

I have array of objects:
[
{_id: "5ca2141da0106d1320c0ae32", detail: 1},
{_id: "5ca2141da0106d1320c0ae33", detail: 3},
{_id: "5ca2141da0106d1320c0ae34", detail: 3}
]
How i can update document by id and its value from array?
I'm trying to do it this way:
arrayOfObjects.map(i => {
ids.push(i._id);
details.push(i.detail);
});
Model.updateMany(
{ _id: { $in: ids } },
{ $set: { detail: details} },
should i get an index of $in: ids for my set operator?
Here is your array.
var arrayofObjects = [
{_id: "5ca2141da0106d1320c0ae32", detail: 1},
{_id: "5ca2141da0106d1320c0ae33", detail: 3},
{_id: "5ca2141da0106d1320c0ae34", detail: 3}
]
arrayOfObjects.forEach(function(obj) {
Model.update({"_id": obj._id}, {"$set": {"detail": obj.detail}}, callback);
});
UpdateMany is db.Collection collection object. Refer link.
Prior to Mongo version 4.2 you have to execute each update separately as they have different conditions, this is best done using bulkWrite in order to save up on network overhead, like so:
const input = [
{_id: ObjectId("5ca2141da0106d1320c0ae32"), detail: 1},
{_id: ObjectId("5ca2141da0106d1320c0ae33"), detail: 3},
{_id: ObjectId("5ca2141da0106d1320c0ae34"), detail: 3}
];
const bulk = [];
input.forEach((datum) => {
bulk.push(
{
updateOne: {
"filter": {_id: datum._id},
"update": {$set: {detail: datum.detail}}
}
}
)
})
await db.collection.bulkWrite(bulk)
Version 4.2 introduced pipelined updates which allows us to use aggregation operators in the update body, now we can execute a single update and leverage this power, you can achieve the update in multiple ways here is one example:
const input = [
{_id: ObjectId("5ca2141da0106d1320c0ae32"), detail: 1},
{_id: ObjectId("5ca2141da0106d1320c0ae33"), detail: 3},
{_id: ObjectId("5ca2141da0106d1320c0ae34"), detail: 3}
];
db.collection.updateMany(
{ _id: {$in: input.map(v => v._id )}},
[
{
$set: {
detail: {
$getField: {
field: "detail",
input: {
$first: {
$filter: {
input: input,
cond: {
$eq: [
"$$this._id",
"$_id"
]
}
}
}
}
}
}
}
}
])
Mongo Playground

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

How to use more then $group in mongoose

[
{
"_id":"56569bff5fa4f203c503c792",
"Status":{
"StatusID":2,
"StatusObjID":"56559aad5fa4f21ca8492277",
"StatusValue":"Closed"
},
"OwnerPractice":{
"PracticeObjID":"56559aad5fa4f21ca8492291",
"PracticeValue":"CCC",
"PracticeID":3
},
"Name":"AA"
},
{
"_id":"56569bff5fa4f203c503c792",
"Status":{
"StatusID":2,
"StatusObjID":"56559aad5fa4f21ca8492277",
"StatusValue":"Open"
},
"OwnerPractice":{
"PracticeObjID":"56559aad5fa4f21ca8492292",
"PracticeValue":"K12",
"PracticeID":2
},
"Name":"BB"
}
]
In above json response,
How to group by PracticeValue,StatusValue into single function,
the below code to be used to group only StatusValue,please help how to group Practice value with the same function,
Opp.aggregate([
{$group: {
_id: '$Status.StatusValue',
count: {$sum: 1}
}}
], function (err, result) {
res.send(result);
});
and my response is,
[
{
"_id":"Deleted",
"count":0
},
{
"_id":"Open",
"count":1
},
{
"_id":"Closed",
"count":1
}
]
please help me, how to use more then $group function..
You can group by multiple fields like this:
var resultAggr = {Status: [], Practice: []};
Opp.aggregate(
[
{$group: { _id: '$Status.StatusValue', count: {$sum: 1} }}
], function (err, statusResult) {
resultAggr.Status = statusResult;
Opp.aggregate(
[
{$group: { _id: '$OwnerPractice.PracticeValue', count: {$sum: 1} }}
], function (err, practiceResult) {
resultAggr.Practice = practiceResult;
res.send([resultAggr])
});
});

Resources