Mongoose find with multiple matches
I am new to this technology and am working with a Node and Express server that Mongoose uses. I have the following schema for a collection of documents.
var empSchema = new mongoose.Schema({
_id: String,
orgName: {type: String, required: true},
locName: {type: String, required: true},
empName: {type: String, required: true}
});
Here I am getting a list of location names like "NewYork", "London", "Paris" etc ... in the request and should return documents in the response like the following ....
{
result:[{locName:"NewYork",
empList:[
{orgName:"abc", empName:"emp1"},
{orgName:"xyz", empName:"emp2"}]
},
{locName:"London",
empList:[
{orgName:"pkq", empName:"emp13"},
{orgName:"mns", empName:"emp23"}]
}]
}
What would be the best way to use mongoose from Node. I think making multiple queries (each with place) in mongodb is a bad idea.
Is there a way to get the expected json response with one mongoose call? Thank.
source to share
Yes, use an aggregation framework to get the desired result. Aggregation pipeline will consist of a stage , which includes documents on the field and to add fields and the array . The last statement in the stage replaces the field from the previous aggregation stream with the new field . $group
locName
$addToSet
orgName
empName
empList
$project
_id
locName
To demonstrate this concept, suppose you have a sample collection that you paste with the mongo shell:
db.employees.insert([
{
_id: "1",
orgName: "abc",
locName: "New York",
empName: "emp1"
},
{
_id: "2",
orgName: "xyz",
locName: "New York",
empName: "emp2"
},
{
_id: "3",
orgName: "pkq",
locName: "London",
empName: "emp13"
},
{
_id: "4",
orgName: "mns",
locName: "London",
empName: "emp23"
}
])
The following aggregation gives the desired result:
db.employees.aggregate([
{
"$group": {
"_id": "$locName",
"empList": {
"$addToSet": {
"orgName": "$orgName",
"empName": "$empName"
}
}
}
},
{
"$project": {
"_id": 0,
"locName": "$_id",
"empList": 1
}
}
])
Output
/* 0 */
{
"result" : [
{
"empList" : [
{
"orgName" : "mns",
"empName" : "emp23"
},
{
"orgName" : "pkq",
"empName" : "emp13"
}
],
"locName" : "London"
},
{
"empList" : [
{
"orgName" : "xyz",
"empName" : "emp2"
},
{
"orgName" : "abc",
"empName" : "emp1"
}
],
"locName" : "New York"
}
],
"ok" : 1
}
In Mongoose, you can use an aggregation pipeline like this:
Employee.aggregate()
.group({
"_id": "$locName",
"empList": {
"$addToSet": {
"orgName": "$orgName",
"empName": "$empName"
}
}
})
.project({
"_id": 0,
"locName": "$_id",
"empList": 1
})
.exec(function (err, res) {
if (err) return handleError(err);
console.log(res);
});
// Or the simple aggregate method
var pipeline = [
{
"$group": {
"_id": "$locName",
"empList": {
"$addToSet": {
"orgName": "$orgName",
"empName": "$empName"
}
}
}
},
{
"$project": {
"_id": 0,
"locName": "$_id",
"empList": 1
}
}
]
Employee.aggregate(pipeline, function (err, res) {
if (err) return handleError(err);
console.log(res);
});
source to share
All queries when you need to group sum values, called aggregate. You can read about this in the mongo docs and the same methods have a model in Mongoose . To create a request, you can use the following code:
Employee
.aggregate()
.group({ _id: '$locName', empList: { $push: "$$ROOT" }})
.exec(function (err, res) {
});
If you don't need to query the entire table, there is also a match method .
source to share