Mongoose compare with a third level nested field value - node.js

I have the following collections:
and I would like to do a find from collection1 all the way to collection 3 and 4 to compare name in one query.
example:
collection1.find({
collection2.collection3.name: req.body.name3,
collection2.collection4.name: req.body.name4
}).exec()

You need to use lookup, unwind and match, here is untested solution of your problem
Model.aggregate([
{
$match: {
_id: req.params.id
// for object id use
// _id: mongoose.Types.ObjectId(req.params.id)
}
},
{
$lookup: {
from: "collection2",
localField: "collection2",
foreignField: "_id",
as: "Collection2"
}
},
{
$unwind: "$ColelctionTwo"
},
{
$lookup: {
from: "collection3",
localField: "CollectionTwo.collection3",
foreignField: "_id",
as: "Collection3"
}
},
{
$lookup: {
from: "collection4",
localField: "CollectionTwo.collection4",
foreignField: "_id",
as: "Collection4"
}
}
]).exec(function(err, result) {
if(err) {
// handle here
}
if(result) {
// do something here...
}
}

You can use mongodb aggregate framework's $lookup or $graphlookup stages for multi collection queries. Mongoose docs for aggregation https://mongoosejs.com/docs/api.html#Aggregate
You cannot do a simple find query for multi collection lookups.

Related

Facing a problem for retrieving nested collection data using Mongodb query

I have a three collections, names are "Category", "Subcategory" and "Services". I have tried an aggregate query but I am not able to populate desired result.
I need output as below.
https://www.screenpresso.com/=4LBTc
I have tried the below query
PlumbingList:async(req,res)=>{
const result=await Categoriesmodel.
find()
.aggregate([
{$lookup:{from:"subCategory",localField:"_id",foreignField:"SubCategoryId",as:"sub_category"}},
{$lookup:{from:"Services",localField:"_id",foreignField:"Services_id",as:"service_list"}}
]);
res.json({message:"categories list",result})
}
Can anyone let me know where I am wrong?
const sync = async (req, res) => {
const result = await Categoriesmodel.aggregate([
{
$lookup: {
from: "subCategory",
localField: "SubCategoryId",
foreignField: "_id",
as: "sub_category",
},
},
{
$lookup: {
from: "Services",
localField: "Services_id",
foreignField: "_id",
as: "service_list",
},
},
]);
res.json({ message: "categories list", result });
};

get _id based on value from a collection for a array and insert in mongodb collection

Input:
[{"gradeName":1,"sectionName":"a","maximumStudents":12},{"gradeName":2,"sectionName":"b","maximumStudents":13}]
In mongodb how to get the _id of gradeName and sectionName from two collection and store in the third collection say mergeddetails
mergeddetails:
[{"grade_id":"60f819e04a9d43158cabad55","section_id":"60f819e04a9d43158cabad54","maximumStudents":12},{"grade_id":"60f819e04a9d43158cabad59","section_id":"60f819e04a9d43158cabad5b","maximumStudents":13}]
where grade_id is the _id of corresponding gradeName,section_id is the _id of corresponding sectionName
please help with with mongodb quire i am using nodejs to write the API
You need to use $lookup for both the collections
db.student.aggregate([
{ $lookup:
{ from: "grade",
localField: "gradeName",
foreignField: "grade",
as: "grade"
}
},
{$lookup:
{ from: "section",
localField: "sectionName",
foreignField: "section",
as: "section"
}
},
{ $unwind: "$grade" },
{ $unwind: "$section" },
{$project:
{
_id:0,
"grade_id":"$grade._id",
"section_id":"$section._id",
maxStudent:1
}
}
])

MongoDB: $match on a nested document after $lookup

I need to query a collection of timecards which are linked to jobs, while jobs are linked to facilities with a specific facility ID. I have the following aggregation query:
Timecard.aggregate([
{ $match: query }, //some query parameters set before, doesn't matter here
{
$lookup: {
from: 'jobs',
as: 'job',
localField: 'job',
foreignField: '_id'
}
},
{ $unwind: '$job' },
{
$lookup: {
from: 'facilities',
localField: 'job.facilityId'
foreignField: '_id',
as: 'job.facilityId'
}
},
{ $unwind: '$job.facilityId' },
{ $match: {'job.facilityId._id':'5cad048d95d61a002f5a9edb'}}
];)
Everything before the last $match works just fine, jobs are populated into timecards, facilities are populated into jobs. But the match doesn't work for some reason. However, if I add facilityId field with
{$addFields: {facilityId: '$job.facilityId._id'}}
and change the $match to
{$match: 'facilityId':'5cad048d95d61a002f5a9edb'}
then it works.
The question is, is there a way to query a subdocument's field with dot notation this way?
Your last line likely needs to be an ObjectId
{ $match: {'job.facilityId._id': ObjectId('5cad048d95d61a002f5a9edb')}}

NodeJs mongoose performance slow when compared with mongo shell or robo3t performance

I am running a query that prints around 300 results using aggregate.
The query is super fast when executed in robo3t/mongo shell but super slow when done using mongoose in NodeJs.
Tried finding for an answer, landed on this link tried setting DBQuery.shellBatchSize = 500000; but difference b/w two queries is still around 7-8 secs
Also, updated the mongoose and mongodb version to the latest one today itself.
here is the query:
db.getCollection('fixed_activities').aggregate([
{
$lookup: {
from: "city",
localField: "activity_city",
foreignField: "_id",
as: "activity_location"
}
},
{
$lookup: {
from: "rate_sheet_activity_prices",
localField: "_id",
foreignField: "act_id",
as: "rate_sheets"
}
},
{
$lookup: {
from: "organizations",
localField: "rate_sheets.rate_sheet_id",
foreignField: "rate_sheets.rate_sheet_id",
as: "org_id"
}
},
{
$lookup: {
from: "images",
localField: "activity_image",
foreignField: "_id",
as: "activity_image"
}
},
{ $match: { org_id: { $exists: true, $not: { $size: 0 } } } }
])
I had the same problem, my solution was to switch from mongoose to the native mongodb controller in nodejs.
https://mongodb.github.io/node-mongodb-native/3.3/installation-guide/installation-guide/

Getting Mongoose Error: Arguments must be aggregate pipeline operators

I'm trying to run this aggregations but I cannot get a result with aggregation option parameter, what is wrong ? Here is my aggregation:
var coupons = couponModel.aggregate(
[
{
"$lookup": {
from: "campaigns",
localField: "campaignId",
foreignField: "_id",
as: "campaigns"
}
},
{ "campaignId": { "$in": campaignsIds } },
],
{
allowDiskUse: true,
explain: true
}
);
Also Try Different Structure:
couponModel.aggregate(
[
{
"$lookup": {
from: "campaigns",
localField: "campaignId",
foreignField: "_id",
as: "campaigns"
}
},
{ "campaignId": { "$in": campaignsIds } },
],
function(err,result) {
if (err) return handleError(err);
// Result is an array of documents
console.log(result);
}
)
When using mongoose you cannot pass an object as the second parameter of aggregate(). Instead you must use mongoose functions. Also, in the second object of your pipeline you forgot to specify the aggregation stage. So your code would look like this:
var coupons = couponModel.aggregate(
[
{
"$lookup": {
from: "campaigns",
localField: "campaignId",
foreignField: "_id",
as: "campaigns"
}
},
{ $match: { "campaignId": { "$in": campaignsIds } } }
]
)
.allowDiskUse(true)
.explain(true);

Resources