How use aggregate and match in mongodb? - javascript

I have two collection ProductInventories and ProductDetails. The ProductInventories has a prodId that is connected to the id of ProductDetails. I want to get all the product that is Active only.
const products = await ProductInventory.find().populate({
path: 'prodId',
model: ProductDetails,
populate: { path: 'category', select: 'category_name', model: Category },
});
I'm using this code to get all the data, but I want to have a condition that it will return the item that is isActicve = True. I'm just using a filter function to filter all active data. I want to learn how to use aggregate and match.

You can first use the lookup aggregation from ProductInventories to ProductDetails based on the prodId field, then do a match aggregation with field isActive = true
db.ProductInventories.aggregate([
{
$lookup: {
from: "ProductDetails",
localField: "prodId",
foreignField: "id",
as: "product_details"
},
$match: {
isActive: true
}
}
])
Refer https://docs.mongodb.com/manual/reference/operator/aggregation/match/
https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/

This is my updated code and its working now. Thanks also for helping #smitha t m.
const products = await ProductInventory.aggregate([
{
$lookup: {
from: 'productdetails',
localField: 'prodId',
foreignField: '_id',
as: 'product',
},
},
{
$unwind: '$product',
},
{
$match: { 'product.isActive': true },
},
]);

Related

MongoDB count all likes and posts for a single user using the aggregation pipeline

I need an endpoint that returns the user's info, amount of post's they've submitted and the sum of all likes their post's have received.
I'm using MongoDB for my database along with Mongoose for my Node server.
These are my models:
var userSchema = new Schema({
'username' : String,
'email' : String,
'password' : String
});
var photoSchema = new Schema({
'text' : String,
'path' : String,
'timestamp': Number,
'postedBy' : {type: Schema.Types.ObjectId, ref: "user"}
});
var likeSchema = new Schema({
'timestamp' : Number,
'photo' : {type: Schema.Types.ObjectId, ref: 'photo'},
'user' : {type: Schema.Types.ObjectId, ref: 'user'}
});
I've already accomplished this by using Javascript and multiple queries:
// Get user
let user = await userModel.findOne({_id: mongoose.Types.ObjectId(id)})
.select("_id, username")
.lean()
.exec();
// Get all users photos
let photos = await photoModel.find({postedBy: mongoose.Types.ObjectId(user._id)})
.select("_id")
.exec();
// Sum likes for all photos
let likes = 0;
for (let i = 0; i < photos.length; i++)
likes += (await likeModel.find({photo: photos[i]._id}).exec()).length;
But I want to try it with the aggregate pipeline. This is my failed attempt:
let user = await userModel.aggregate(
[
{
$match: {_id: mongoose.Types.ObjectId(id)}
},
{
$unset: ["email", "password", "__v"]
},
{
$lookup: {
from: "photos",
localField: "_id",
foreignField: "postedBy",
as: "photos"
}
},
{
$lookup: {
from: "likes",
localField: "photos._id",
foreignField: "photo",
as: "likes"
}
},
{
$unwind: "$photos"
},
{
$group: {
_id: "$_id",
username: {$first: "$username"},
postCount: {$sum: 1},
likeCount: {$sum: 1}
}
}
]);
I don't know how to get the number of likes for each photo post. Is it possible in a single aggregation pipeline?
Would it make more sense to build it with multiple aggegation pipelines or even just with multiple queries?
If you use $size to get the size of each array, you won't need the unwind or group stages.
[
{$match: {_id: mongoose.Types.ObjectId(id)}},
{$lookup: {
from: "photos",
localField: "_id",
foreignField: "postedBy",
as: "photos"
}},
{$lookup: {
from: "likes",
localField: "photos._id",
foreignField: "photo",
as: "likes"
}},
{$project: {
likeCount: {$size:"$likes"},
postCount: {$size:"$photos"}
}}
]
Playground
Alternately, since the only field you are getting from the user collection is _id, which you already have, you can skip the match and lookup, and just aggregate the photos collection directly:
photoModel.aggregate([
{$match: {postedBy: mongoose.Types.ObjectId(id)}},
{$lookup: {
from: "likes",
localField: "_id",
foreignField: "photo",
as: "likes"
}},
{$group: {
_id: "$postedBy",
likeCount: {$sum:{$size:"$likes"}},
postCount: {$sum:1}
}}
])
Playground

Conditional joins on collections using mongoose

I'm new to mongoDB, I am trying to achieve the following SQL query on it. but could not find anything useful so far. can anyone tell equivalent mongoose query
select * from interviews
inner join candidate on interviews.clientId = candidate._id
inner join billing on appointment._id = billing.appointmentId
where ('
interviews.status= "upcoming",
interviews.startTime= "2017-01-01",
candidate.clientAgeGroup= "adult",
candidate.candidatetatus= "new",
billing.paymentStatus= "paid"
')
what I got so far is following
const [result, err] = await of(Interview.find({ ...filterQuery }).limit(perPage)
.skip(perPage * page)
.sort({
startTime: 'asc'
})
.populate([{ path: 'candidateId', model: 'Candidate', select: 'firstName status avatar' },
{ path: 'billingId', model: 'Billing', select: "status" }]));
UPDATE
I have following name and export scheme
//interview.model.js => mongodb show name as interview
module.exports = mongoose.model('Interview', interviewSchema);
//candidate.model.js => mongodb show name as candidate
module.exports = mongoose.model('Candidate', candidateSchema);
You can use filter out objects included in resulting array using match but in the case if it couldn't find any, it would still return a null value. So in comparison this works similar to sql left join.
const [result, err] = await of(Interview.find({ ...filterQuery }).limit(perPage)
.skip(perPage * page)
.sort({
startTime: 'asc'
})
.populate([{ path: 'candidateId', model: 'Candidate', select: 'firstName status avatar', match: {clientAgeGroup: "adult", candidatetatus: "new"} },
{ path: 'billingId', model: 'Billing', select: "status", match: {paymentStatus: "paid"} }]));
Also see https://mongoosejs.com/docs/populate.html#query-conditions
If you need strictly a inner join then you can use mongodb aggregate pipeline.
Interview.aggregate([
{
"$match": {
status: "upcoming",
startTime: "2017-01-01",
}
},
{
'$lookup': {
'from': 'candidates', // this should be your collection name for candidates.
'localField': 'candidateId', // there should be an attribute named candidateId in interview model that refer to candidate collection
'foreignField': '_id',
'as': 'candidates'
}
}, {
'$match': {
'candidates.clientAgeGroup': "adult",
'candidates.candidatetatus': "new"
}
},
{
'$lookup': {
'from': 'billing', // this should be your collection name for billing.
'localField': 'billingId', // there should be an attribute named billingId in interview model that refer to billing collection
'foreignField': '_id',
'as': 'billing'
}
}, {
'$match': {
'billing.paymentStatus': "paid"
}
},
{ "$sort": { startTime: 1 } },
{ "$limit": perPage },
{ "$skip": perPage * page }
])

mongoose $aggregate $lookup does not returns data

I have below code
Users.aggregate([{
$match: dt //working fine
}, {
$lookup: { //not working returns []
from: "points",
localField: "_id", //field in user collection
foreignField: "user", //field in points collection
as: "points"
}
}, {
$lookup: {
from: "orders", //not working returns []
localField: "_id", //field in user collection
foreignField: "user_id", //field in orders collection
as: "orders"
}
}], (err, data) => {
return res.status(200).json({
message: "success",
data: data ? data : [],
status: true
})
})
there are 16 records in points and orders collections but it always returns empty array.
I am unable to find the issue. Please help.
in points and orders collections user id is added.
Is there any other way to find data in these collections with user table? I didn't find anything except populate to do so.
MongoDB server version: 3.6.9
"mongoose": "^5.3.4"

MongoDb-Node:Agregation node-mongo query for chat

im new on mongo and want to get data for a chat, let me explain.
i have a colection of messages:
_id:id
viewed:boolean
created_at:date
text:String
receiver:ObjectId
emitter:ObjectId
i want all the list of messager for a certain emitter and receiver order by the date (like a normal chat)
i have tryed aggregation like this:
db.messages.aggregate(
[
{
$lookup: {
from: "users",
localField: "emitter", // field in the orders collection
foreignField: "_id", // field in the items collection
as: "fromItems"
}
},
{
$match: {
'emitter':ObjectId("5c8917b4ef9ebf2e608c68dc")
}
}
,
{
$addFields: {
ids: { _id: "$_id" } ,
created: { created_at: "$created_at" }
}
},
{
$group:
{
_id: { tot:["$emitter", "$receiver"] },
text: { $addToSet:"$text"},
}
},
{
$sort: {created_at: 1}
}
]
)
But this gives me an array of messages only of a certain emitter and dont give me the date or the viewed data.
Im really new on mongo and node so if someone can help me with a explain will be great.
Thanks for reading and sory for the bad english
You must include date or the viewed data in $group stage.
Try with this.
{
$group:
{
_id: { tot:["$emitter", "$receiver"] },
text: { $addToSet:{text:"$text",created:"$created.created_at"}},
created_at:{$last:"$created.created_at"}
}
},
Why there is ids and need for tot fields and created as a object ??

Mongoose, get child document and group by

I'm trying to get some results and group the by an id, but I don't know a way to do that, I was trying with $unwind and $lookup, but when I use the $group, it doesn't give me results, so, I will appreciate any feedback.
usercalification model
{
calification: Number,
status: Number,
place: {
type: Schema.ObjectId,
ref: 'Place',
}
}
place model
{
name: String,
description: String
}
I was trying to do something like this:
mongoose.model('usercalification').aggregate([
{
$lookup: {
from: 'places',
localField: 'place',
foreignField: '_id',
as: 'places'
}
},
{
{
$unwind: '$places'
}
}
]);
It works like it should, the issue is when I try to $groupBy
mongoose.model('usercalification').aggregate([
{
$lookup: {
from: 'places',
localField: 'place',
foreignField: '_id',
as: 'places'
}
},
{
{
$unwind: '$places'
}
},
{
$group: {
_id: '$place',
calification: { $avg: '$calification' },
count: {$sum: 1}
}
}
]);
I'm grouping by $place cuz that's the Place Id that I need to group by.
I'll appreciate any feedback.
The issue was that those were not ordered in the correct way.

Categories