I'm trying to write a Mongoose aggregation query to get the sum of a field for all matching documents.
Meaning I have a model that looks like:
{
itemNumber: String,
quantity: Number
}
There are multiple documents with the same itemNumber, I'm looking to get the sum of the quantity fields.
What's the easiest way to do this?
use group
db.collection.aggregate([
{
$group: {
_id: "$itemNumber",
count: {
$sum: "$quantity"
}
}
}
])
mongoplayground
Related
There are two collections. Catalog collection and order Collection. Catalog collection contains seller id , and compelete product details.
Order collection contains order details like ids of ordered products and buyer details.
My problem is how can I get the complete product details when fetching an order .
order collection is given below
this is the order collection. It contains product Id. I need to get the details of products when fetching orders. Problem is that there is no seperate collection for products. Products are present inside 'catalog' collection
Catalog Collection is given below:
this is the catalog collection.It contains an array of products. so the products are present there
I need to get product details when fetching order details
const order = await Order.find().populate("products");
I am not sure I understand your question entirely but hope should help you:
Plan
unwind products
lookup product with _id of product in catalog.products
unwind the lookup result because result of lookup stage is an array
group this back together
Implementation
const result = await orderModel.aggregate()
.unwind('products')
.lookup({
from: 'catalogs',
let: { product_id: '$products' }, // in order
pipeline: [
{
$unwind: '$products' // $expr cannot digest arrays so we need to unwind which hurts performance...
},
{
$match: { $expr: { $eq: ['$products._id', '$$product_id'] } }
},
{
$project: { _id: 0, products: 1 } // only care products in catelog
}
],
as: 'productDetail'
})
.unwind('productDetail')
.group({
_id: '$_id',
seller: { '$first': '$seller' },
buyer: { '$first': '$buyer' },
products: {
$push: '$productDetail.products'
}
});
However, I don't recommend doing it this way as it can be resource intensive... I suggest you change your database design eg separating product into a separate collection for easier querying.
I have a MongoDB collection called users with documents that look like:
{
_id: ObjectId('123'),
username: "abc",
avatar: "avatar/long-unique-random-string.jpg",
connections: [ObjectId('abc'), ObjectId('xyz'), ObjectId('lmn'), ObjectId('efg')]
}
This document belongs to the users collection.
What I want to do:
First, find one document from the users' collection that matches _id -> '123'.
Project the connections field received from step 1, which is an array of ObjectIds of other users within the same collection.
Find all documents of users from the array field projected in step 2.
Project and return an array of only the username and avatar of all those users from step 3.
While I know that I can do this in two separate queries. First using findOne which returns the friends array. Then, using find with the results of findOne to get all the corresponding usernames and avatars.
But, I would like to do this in one single query, using the aggregation pipeline.
What I want to know, is it even possible to do this in one query using aggregation?
If so, what would the query look like?
What, I currently have:
await usersCollection
.aggregate([
{ $match: { _id: new ObjectId(userId) } },
{ $project: { ids: "$connections" } },
{ $match: { _id: { $in: "ids" } } },
{
$project: {
username: "$username",
avatar: { $ifNull: ["$avatar", "$$REMOVE"] },
},
},
])
.toArray()
I know this is wrong because each aggregation stage receives the results from the previous stage. So, the second match cannot query on the entire users' collection, as far as I know.
I'm using MongoDB drivers for nodeJS. And I would like to avoid $lookup for possible solutions.
I am working on nestjs and I have a collection where 5 documents are saved and each document has a property name 'price'. I want to fetch price property from every document and need to sum up all and shows that sum as an output. How do I achieve this?
Use aggregate
.aggregate([
{
$group: {
_id: '',
sumPrices: { $sum: '$price' }
}
])
I have a collection of videos, each video doc has user_id.
I need to get the last 5 videos of each user.
don't know where to start... tried grouping without any success.
any help would be appreciated.
give this pipeline a try:
db.collection.aggregate([
{
$sort: { _id: -1 }
},
{
$group: {
_id: "$user_id",
videos: { $push: "$$ROOT" }
}
},
{
$project: {
_id: 0,
user_id: "$_id",
videos: { $slice: ["$videos", 5] }
}
}
])
https://mongoplayground.net/p/6NOOJDnfIhk
explanation:
with the first stage, you $sort the whole collection in descending order on the _id field. sorting initially is necessary because there's no operator in mongo that can sort the grouped items afaik.
then you group by user_id field. we $push all documents of each group to a new field called videos. $$ROOT variable gives you access to all docs of each group.
the final $project stage uses $slice to pick only the top 5 items in the videos array from the previous stage and sets it on a field of the same name.
query to find all the elements in the array in mongoose dynamically
below is the object
var res1= {
"category":["travel","cafe"],
"amount":"300"
}
There could be more elements in the category but I want to create the query which automatically finds all the elements in the database just like forEach works
The $in operator should to the trick. $in will look for documents where the provided field matches any of the values in the array. the query would look like this:
Detail.find({
category: { $in: ["travel", "cafe"] },
amount: 300
})
assuming the filters are coming in dynamically on the request, and that req.body.categories is an array of desired categories:
Detail.find({
category: { $in: req.body.categories },
amount: req.body.amount
})