filteredListings = await Listing.aggregate([
{ $match: { category: req.params.category } },
{ price: { $lt: 150 } }
]);
As you can see, I'm trying to get all listings with a field price of less than 150. what is the correct way of doing that?
You need to add it in $and operator inside the $match statement
filteredListings = await Listing.aggregate([
{ $match: { $and: [{ category: req.params.category }, { price: { $lt: 150 } }] } }
]);
Related
I am writing a query to do aggregation with respect to one field, however, I want to exclude this aggregation for one value of that field
let coAuthorCutThreshold =100
network.aggregate([
{ $group: { _id: '$title', title :{$ne: "class notes"}, count: { $sum: 1 } }} ,
{ $match: { count: { $gt: coAuthorCutThreshold } } },
{ $sort: { count: -1 } }
]).forEach(function (obj) {
cutTitles.push(obj._id)
});
I want to do aggregation with respect to title but do to not want to do aggregation where the title is "class notes". I tried many command but did not work
I want to include all those values in cutTitles except where title is "class notes"
Match in order to filter out the documents you don't want to group before the group stage.
let coAuthorCutThreshold = 100
network.aggregate([
{ $match: { title: { $ne: "class notes" }}},
{ $group: { _id: '$title', count: { $sum: 1 }}},
{ $match: { count: { $gt: coAuthorCutThreshold }}},
{ $sort: { count: -1 }}
]).forEach(function (obj) {
cutTitles.push(obj._id)
});
I currently have a Mongo query that looks like this:
const user = await User.findOne({ userId }).lean() || []
const contributions = await Launch.aggregate([
{ $sort: { addedAt: -1 } },
{ $limit: 10 },
{
$match: {
_id: { $in: user.contributions }
}
},
{
$addFields: {
activity: 'contribution',
launchName: '$name',
launchId: '$_id',
date: '$addedAt',
content: '$description'
}
}
])
But instead of having two different Mongo queries (findOne and aggregate), how can I combine them into one query?
I tried this but it just errors out immediately in the lookup part:
const contributions = await Launch.aggregate([
{ $sort: { addedAt: -1 } },
{ $limit: 10 },
{
$lookup: {
from: 'user',
let: { id: $user.contributions },
pipeline: [
{ $match: { $expr: { $in: [$_id, $$user.contributions] } } }
],
localField: '_id',
foreignField: 'userId',
as: 'user'
}
},
{
$addFields: {
activity: 'contribution',
launchName: '$name',
launchId: '$_id',
date: '$addedAt',
content: '$description'
}
}
])
I've never used the pipeline option so a little confused onn how to fix this problem?
Enclose these $user.contributions, $_id with quotes in order to make the query valid.
Since you declare the id variable with the value of user.contributions. You should use the variable with $$id instead of $$user.contributions.
I don't think the localField and foreignField are needed as you are mapping/joining with pipeline.
Your aggregation query should be looked as below:
const contributions = await Launch.aggregate([
{ $sort: { addedAt: -1 } },
{ $limit: 10 },
{
$lookup: {
from: 'user',
let: { id: "$user.contributions" },
pipeline: [
{ $match: { $expr: { $in: ["$_id", "$$id"] } } }
],
as: 'user'
}
},
{
$addFields: {
activity: 'contribution',
launchName: '$name',
launchId: '$_id',
date: '$addedAt',
content: '$description'
}
}
])
got this error: arguments must be aggregate pipeline operators
this is the course 'Schema" that got bootcamp as objectId.
const CourseSchema = new mongoose.Schema({
bootcamp: {
type: mongoose.Schema.ObjectId,
ref: 'Bootcamp',
required: true
}
});
the aggregation :
//static method to get avg of course tuitions
CourseSchema.statics.getAverageCost = async function (bootcampId) {
console.log('calculating avg cost... with bootcampId:' + bootcampId);
const obj = await this.aggragate([{
$match: { bootcamp: bootcampId },
$group: {
_id: '$bootcamp',
averageCost: { $avg: '$tuition' }
}
}]);
console.log(obj);
}
calling for the aggregation before saving or removing:
...
// Call getAvarageCost after save
CourseSchema.post('save', function () {
this.constructor.getAverageCost(this.bootcamp);
})
// Call getAvarageCost before remove
CourseSchema.post('remove', function () {
this.constructor.getAverageCost(this.bootcamp);
})
...
$match and $group must be in different pipeline operations
const cursor = this.aggregate([
{ $match: { bootcamp: bootcampId } },
{
$group: {
_id: '$bootcamp',
averageCost: { $avg: '$tuition' },
},
},
])
console.log(await cursor.toArray())
I have documents of a collection that look like following:
{
items: [
{
price: 80
},
{
price: 70
}
]
},
{
items: [
{
price: 100
},
{
price: 85
}
]
},
{
items: [
{
price: 200
},
{
price: 85
}
]
},
...
I want to be able to query all documents with MyObj.find(query) where the sum of all item prices is between a given range. For example, $gte 160 and $lte 200 which would only return me the document the second document in the example.
const query = ???
const filteredDocs = await MyObj.find(query).exec()
How would the query for this look like?
In this case, you can use aggregation. First, add field represent the sum of items price with $addFields and $sum then find document has that field match your conditions. Something like:
MyObj.aggregate([
{
$addFields: {
total: {
$sum: "$items.price"
}
}
},
{
$match: {
total: {
$gte: 160,
$lte: 200
}
}
},
])
Mongo Playground
EDIT: If you only want to use find(), you can try $expr:
MyObj.find({
$expr: {
$and: [
{
$gte: [
{
$sum: "$items.price"
},
160
]
},
{
$lte: [
{
$sum: "$items.price"
},
200
]
}
]
}
})
Mongo Playground
I am new to MongoDB and I am stuck in the below scenario.
I have a collection that contains duplicate docs.
I just want to get the sum of the property in each doc excluding the duplicate docs.
My Docs looks like this:
{"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"319723fb80b1a297cf0803abad9bc60787537f14a6a37d6e47",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":10,
"transactionId":"319723fb80b1a297cf0803abad9bc60787537f14a6a37d6e47",
"uid":"2019-11-20T17:39:17.405Z",
"createdAt":"2019-11-21T08:56:56.589+00:00",
"updatedAt":"2019-11-21T08:56:56.589+00:00","__v":0
},
{
"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":50,
"transactionId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"uid":"2019-11-20T17:39:17.405Z",
},
{
"_id":"5dd629461fc50b782479ea90",
"referenceId":"5dd581f10859d2737965d23a",
"sellingId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"account_name":"mrfsahas1234",
"vendor_name":"testaccount2",
"action_type":"purchase",
"product_name":"Bottle",
"product_quantity":50,
"transactionId":"320a9a2f814a45e01eb98344c9af708fa2864d81587e5914",
"uid":"2019-11-20T17:39:17.405Z",
},
Currently, I am doing this:
MaterialsTrack.aggregate([
{
$match: {
$and: [
{product_name: product_name},
{account_name: account_name},
{action_type: 'purchase'},
{uid:uid}
]
}
},
{
$group: {_id: "$sellingId", PurchseQuantity: {$sum: "$product_quantity"}}
},
])
It returns the sum of product_quantity all the matching docs (including the duplicate docs).
Current Output:
{_id: "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914", PurchseQuantity:110}
Expected Output:
{_id: "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914", PurchseQuantity:60}
I want to get the sum of only unique docs. How can I achieve it?
Thanks in advance!
You need to sum inside of the $group _id field, and then use the replaceRoot to achieve the the result you wanted.
MaterialsTrack.aggregate([
{
$match: {
$and: [
{
product_name: "Bottle"
},
{
account_name: "mrfsahas1234"
},
{
action_type: "purchase"
},
{
uid: "2019-11-20T17:39:17.405Z"
}
]
}
},
{
$group: {
_id: {
sellingId: "$sellingId",
PurchaseQuantity: {
$sum: "$product_quantity"
}
}
}
},
{
$replaceRoot: {
newRoot: {
_id: "$_id.sellingId",
PurchaseQuantity: "$_id.PurchaseQuantity"
}
}
}
]);
Sample Output:
[
{
"PurchaseQuantity": 50,
"_id": "320a9a2f814a45e01eb98344c9af708fa2864d81587e5914"
}
]
Playground:
https://mongoplayground.net/p/MOneCRiSlO0
What about adding $addToSet to your aggregations pipeline
MaterialsTrack.aggregate([
{
$match: {
$and: [
{product_name: product_name},
{account_name: account_name},
{action_type: 'purchase'},
{uid:uid}
]
}
},
{
$group: {_id: "$sellingId", PurchseQuantity: {$sum: "$product_quantity"},"list" : {$addToSet : "$list"}}
},
])