$lookup work in MongoDB but doenst work with mongoose - mongodb

I have two Documents:
Category = new Schema({
storeKey: { type: String, required: true },
cod: { type: String, required: true },
name: { type: String, required: true },
visible: { type: Boolean }
},
{
timestamps: {
createdAt: "created",
updatedAt: "updated"
}
}
);
and:
Product = new Schema({
name: { type: String, required: true },
cod: String,
storeKey: { type: String, required: true },
categoryId: String,
description: { type: String, required: true },
price: { type: Number, required: true },
stockQuantity: { type: Number, required: true },
avatar: String,
visible: Boolean
}, {
timestamps: true
});
Query on server whith mongoose to locate products with the aggregate category
Product.aggregate([
{
$lookup: {
from: "Category",
localField: "categoryId",
foreignField: "_id",
as: "category"
}
}]
).exec((error, done) => {
if (error) res.status(500).send({
message: langs[req.query.lang],
error
});
res.status(200).send(done);
});
query on local terminal
db.Product.aggregate(
[{
$lookup: {
localField: "categoryId",
from: "Category",
foreignField: "_id",
as: "category"
}
}])
In the terminal, $lookup works correctly. With mongoose, it brings duplicate records and does not bring existing categories. What is wrong?

#Anthony Winzlet was correct, should be categories (in the pural) would have to leave categories (in the pural) and not category, but also, i had not defined the categoryId field as being an ObjectId in the Product Schema, so it was comparing string with ObjectId. In the tests in the terminal I had saved the server return, which returns the _id fields as strings. Now it's working.Thanks!
const ProductSchema = new Schema({
name: { type: String, required: true },
cod: String,
storeKey: { type: String, required: true },
categoryId: { type: Schema.Types.ObjectId, ref: 'categories' },
description: { type: String, required: true },
price: { type: Number, required: true },
stockQuantity: { type: Number, required: true },
avatar: String,
visible: Boolean
}, {
timestamps: true
});

Related

How to fetch data from multiple collections in MongoDB?

How to fetch data from multiple collections in MongoDB by using a common field and sending data (in those fetched collections) using one response?
Employee Scheema:
const mongoose = require("mongoose");
const employeeSchema = new mongoose.Schema(
{
profilePic: {
type: String,
},
employeeID: {
type: String,
required: true,
},
employeeFirstName: {
type: String,
required: true,
},
employeeLastName: {
type: String,
required: true,
},
birthday: {
type: String,
},
streetNo: {
type: String,
},
city: {
type: String,
},
phoneNumber: {
type: String,
},
jobRole: {
type: String,
required: true,
},
NIC: {
type: String,
required: true,
unique: true,
},
companyEmail: {
type: String,
required: true,
unique: true,
},
status: {
type: String,
required: true,
},
resignDate: {
type: String,
},
jobType: {
type: String,
required: true,
},
candidateID: {
type: String,
required: true,
},
teamID: {
type: String,
},
lastSeen: {
type: String,
},
token: {
type: String,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("employee", employeeSchema);
Acadamic Qualification Scheema:
const mongoose = require("mongoose");
const academicQualificaationSchema = new mongoose.Schema(
{
employeeID: {
type: String,
required: true,
},
ordinaryLevelResult: {
type: Array,
required: true,
},
advancedLevelResults: {
type: Array,
required: true,
},
achievements: {
type: Array,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model(
"academicQualification",
academicQualificaationSchema
);
Professional Qualification Scheema:
const mongoose = require("mongoose");
const proffesionalQualificaationSchema = new mongoose.Schema(
{
employeeID: {
type: String,
required: true,
},
degree: {
type: Array,
required: true,
},
language: {
type: Array,
required: true,
},
course: {
type: Array,
required: true,
},
},
{ timestamps: true }
);
module.exports = mongoose.model(
"proffesionalQualification",
proffesionalQualificaationSchema
);
Controller:
exports.viewEmployees = async (req, res) => {
try {
let accQuali, profQuali;
const employees = await employeeSchema.find();
accQuali = await academicQualificaationSchema.find();
profQuali = await ProffesionalQualificationSchema.find();
if (employees || accQuali || profQuali) {
return res.status(200).json({ data: { employees, profQuali, accQuali } });
} else {
return res.status(404).json({ message: message });
}
} catch (err) {
return res.status(404).json({ err: err.message });
}
};
This controller is working properly and sends all data in 3 collections with the use of one response. But, I am comfortable if I will be able to Fetch data separately for each employee.
If you want to get the data from the three collections for specific employee or employees, you can use an aggregation pipeline with a $lookup stage, as suggested by #1sina1. For example:
db.employee.aggregate([
{
$match: {"employeeID": "IDA"}
},
{
$lookup: {
from: "academicQualification",
localField: "employeeID",
foreignField: "employeeID",
as: "academicQualification"
}
},
{
$lookup: {
from: "proffesionalQualification",
localField: "employeeID",
foreignField: "employeeID",
as: "proffesionalQualification"
}
}
])
As you can see on the playground

mongodb find from array and then from object id by refrence

I want to seach order list with product division id. means i can provide division id and get order list of that perticular division.
I'm trying this query, but it return 0 elements
db.getCollection('orders').find({$or:
[{'orderlist':{"$elemMatch":{'product_id.division_id':ObjectId("5f5b1511a859865ac9b0efe5")}}}]
})
My Order Schema
const orderSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
orderlist: [{
product_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: [true, "Product Id is Required"] },
quantity: { type: Number, required: [true, "Product Quantity is Required"] },
packing_type: { type: String, default: null }
}]
});
My Product Schema
const productSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
division_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Division', required: [true, "Product Division Id is Required"] },
name: { type: String, required: [true, "Product Name is Required"] },
price: { type: Number, required: [true, "Product Price is Required"] },
description: { type: String, required: [true, "Product Description is Required"] },
technical_detail: { type: String, default: null },
packing: { type: String, default: null },
packing_type: { type: String, default: null }
});```
To filter query calls with a ref schema first of all you need to lookup it from the server. In your case, it is a mongoose object id not an object of elements.
To merge schemas I recommend using aggregation.$lookup(aggregation)
db.getCollection('orders').aggregate([
{
$lookup: {
from: 'product',
localField: 'orderlist.product_id',
foreignField: '_id',
as: 'products',
},
},
])

Associate one schema with another

I have my user schema:
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true },
password: { type: String, required: true },
date: { type: Date, default: Date.now },
active: { type: Boolean, default: false }
});
I want to create a leave status schema. Data will be given by only one user about all leave status. I want to associate each one of the leave status to there respective user schema id. I tried leave status schema as the following:
const leaveSchema = new Schema({
leave: [
{
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});
How can i associate my emailid with userschema. Can it be possible? If so, how can i tweak it?
We don't need to associate the schema to get leave based on user, You can use aggregation for that,
db.user.aggregate([
...
{$lookup: {from: "leave", localField: "email", foreignField: "leave.email", as: "leaves"}},
...
]);
Still, If you like to associate two collection, You have to use ref using ObjectId
const leaveSchema = new Schema({
leave: [
{
user: { type: Schema.Types.ObjectId, ref: 'user' }, //Your model name as reference
email: { type: String, required: true },
month: { type: String, required: true },
year: { type: Number, required: true },
earnedleave: { type: Number },
sickleave: { type: Number },
festivalleave: { type: Number },
compoff: { type: Number }
}
]
});

how to search for any value in the document

I want to search for all value present without specifying key explicitly. Is it possible with this type of schema? If so, how can I write my query. I tried to write query with other refs but I am unable to write without specifying key for each.
const pschema = new Schema({
user: {
type: Schema.Types.ObjectId, // combine by id
ref: "users" //existing model reference
},
company: {
empNo: {
type: Number,
required: true
},
status: {
type: String,
required: true
},...
},
personal: {
gender: {
type: String
},
dob: {
type: Date
},...
},
skills: {
type: [String],
required: true
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
}...
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
specialization: {
type: String
},..
}
],
social: {
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},...
}
});
For example: If i give linkedin url if should search in social-linkedin and same if i give c it should search in skills array

Need help to make mongo $lookup query

This is my table structure
Group -> _id,name,description,type
GroupMembers -> _id, group(FK),status,Isinvited, user_id(Fk)
User -> _id,name,email,role
Need :- I want to get groups with its active members (status = true) aslo need the name of users from User collections
Current Code :-
Group.aggregate([
{
$lookup: {
from: "groupmembers",
localField: "_id",
foreignField: "group",
as: "membersList"
}
},
{
$lookup : {
from: "users",
localField: "membersList.user",
foreignField: "_id",
as: "userss"
}
},
{
$match:{"_id" : mongoose.Types.ObjectId("5abe70eb7ede1b695e9342d6")}
},
{
$project:{"_id":1,"name":"$name","member":{"membersList":"$membersList","userss":"$userss"}}
}
])
Getting the response but not in well manners go like ->
[
{
"_id": "5abe70eb7ede1b695e9342d6",
"name": "Welcome To Hobnobbin",
"member": {
"membersList":["Got memebrsLiset from GroupMembers"],
"userss": ["Got users from groupMembers FK "]
}
}
]
How can I get it like
[
{
"_id": "5abe70eb7ede1b695e9342d6",
"name": "Welcome To Hobnobbin",
"member": {
"membersList":["Got memebrsLiset from GroupMembers",user: "Userobject here"],
}
}
]
Collections : ->
var GroupSchema = new Schema({
name: {
type: String,
required: 'Please fill Group name',
trim: true
},
photo:{
type:String
},
type: {
type: [{
type: String,
enum: ['child', 'adult']
}],
required: 'Please select at least one type'
},
description:{
type:String,
default:''
},
pinnedTweet:{
type:String,
default:''
},
/*members: [{
type: Schema.ObjectId,
ref: 'User'
}],*/
jointype: {
type: String,
enum: ['openToJoin', 'openToRequest', 'inviteOnly'],
default: 'openToJoin',
required: 'Please select at least one behavious of group'
},
created: {
type: Date,
default: Date.now
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
createByHobnob: {
type: Boolean,
default: false
},
isWelcomeGroup: {
type: Boolean,
default: false
},
allowPrivateChat: {
type: Boolean,
default: false
}
});
var GroupMemberSchema = new Schema({
user : {
type: Schema.ObjectId,
ref: 'User'
},
group : {
type: Schema.ObjectId,
ref: 'Group'
},
role: {
type: String,
enum: ['member', 'ban', 'moderator', 'admin'],
default: 'member',
required: 'Please select at least one role'
},
is_active: {
type: Boolean,
default: false
},
is_invited: {
type: Boolean,
default: false
},
created: {
type: Date,
default: Date.now
},
allowChat: {
type: Boolean,
default: true
}
});
var UserSchema = new Schema({
firstName: {
type: String,
trim: true,
default: ''
},
lastName: {
type: String,
trim: true,
default: ''
},
displayName: {
type: String,
trim: true
},
email: {
type: String,
unique: true,
lowercase: true,
trim: true,
default: '',
validate: [validateLocalStrategyEmail, 'Please fill a valid email address']
}
});