MongoDB: How to find the relationships between collections in database - mongodb

I have a collection of user which has id, firstName, lastName. id field of user collection has been used in another collection.
Is there any way to find all collection which used user id?
user schema:
let userSchema = new mongoose.Schema({
firstName: {
type: String,
trim: true,
required: true
},
lastName: {
type: String,
trim: true,
required: true
}
},
{
timestamps: true,
usePushEach: true
});
training schema:
var trainingSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
name: {type: String, required: true},
institution: {
instituteName: {type: String, required: true},
type: {type: String, required: true},
address: {
country: String,
state: String,
city: String
}
},
startDate: Date,
endDate: Date,
achievements: String,
createdAt: Date,
updatedAt: Date,
endorsers: [{
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
profilePic: {
container: {type: String,default: null},
name: { type: String, default: null }
},
currentPosition: {type: String,default: ""},
currentWorkingCompany: {type: String,default: ""}
}],
});
In above schema userId come from user collection
Note: similar to this which is available in MYSQL:
SELECT
ke.referenced_table_name 'parent table',
ke.referenced_column_name 'parent column',
ke.table_name 'child table',
ke.column_name 'child column',
ke.constraint_name
FROM
information_schema.KEY_COLUMN_USAGE ke
WHERE
ke.referenced_table_name IS NOT NULL
AND table_schema = 'your_db_name'
ORDER BY ke.referenced_table_name;
Source: here

You probably need MySQL function named join. In MongoDB it is named $lookup and it is part of aggregate function.

Related

How to Populate CartItem schema product details into Order Schema using mongoose

I want to populate the details of products in my order. Currently it is only adding product id inside the products array. I tried a couple of methods but none seems to work.
import mongoose from 'mongoose'
const CartItemSchema = new mongoose.Schema({
product: {type: mongoose.Schema.ObjectId, ref: 'Product'},
quantity: Number,
shop: {type: mongoose.Schema.ObjectId, ref: 'Shop'},
status: {type: String,
default: 'Not processed',
enum: ['Not processed' , 'Processing', 'Shipped', 'Delivered', 'Cancelled']}
})
const CartItem = mongoose.model('CartItem', CartItemSchema)
const OrderSchema = new mongoose.Schema({
products: [CartItemSchema],
customer_name: {
type: String,
trim: true,
required: 'Name is required'
},
customer_email: {
type: String,
trim: true,
match: [/.+\#.+\..+/, 'Please fill a valid email address'],
required: 'Email is required'
},
delivery_address: {
street: {type: String, required: 'Street is required'},
city: {type: String, required: 'City is required'},
state: {type: String},
zipcode: {type: String, required: 'Zip Code is required'},
country: {type: String, required: 'Country is required'}
},
payment_id: {},
updated: Date,
created: {
type: Date,
default: Date.now
},
user: {type: mongoose.Schema.ObjectId, ref: 'User'}
})
const Order = mongoose.model('Order', OrderSchema)
export {Order, CartItem}
I tried doing this:
const create = async (req, res) => {
try {
req.body.order.user = req.profile;
console.log(req);
let order = new Order(req.body.order);
let neworder = await Order.findById(order._id)
.populate("products.product", "name price")
.populate("products.shop", "name")
.exec();
// console.log(order);
let result = await order.save();
sendMail(order);
res.status(200).json(result);
} catch (err) {
return res.status(400).json({
error: errorHandler.getErrorMessage(err),
});
}
};
Also tried using this for poulating the product details but doesnt seem to work!
Order.findById(order._id).populate({ path: "products.product", select: "_id name price" })

how to use find in populate (mongoose)

I want to match a string with employee ID, employee Name , project name
My Models : (employee)
const employeeSchema = new mongoose.Schema(
{
employeeID: { type: String, unique: true, required: true },
departmentID: { type: mongoose.Types.ObjectId, ref: 'Department', default: null },
employeeName: { type: String, required: true },
gender: { type: String, default: "", enum: ["Male", "Female"] },
designation: { type: String, default: "" },
email: { type: String, default: null },
branchName: { type: String, default: "" },
employeeType: { type: String, default: "" },
jobStatus: { type: String, default: "" },
joiningDate: { type: Date, default: "" },
leavingDate: { type: Date, default: "" },
comments: { type: String, default: "" },
managerID: { type: mongoose.Types.ObjectId, ref: 'Employee', default: null },
region: { type: String, default: "" },
}
);
(project)
const projectSchema = new mongoose.Schema(
{
projectName: {type: String, required: true},
tech: {type: String, required: true},
startDate: {type: Date, required:true},
endDate: {type: Date, required:true},
customerID:{type:mongoose.Types.ObjectId, ref:'Customer'}
}
);
(employee-Project)
const employeeProjectSchema = new mongoose.Schema(
{
empID: {type: mongoose.Types.ObjectId, required: true, ref: 'Employee'},
projectID: {type: mongoose.Types.ObjectId, required: true, ref: 'Project'},
allocation: {type: [Number]},
assignStartDate: {type: Date},
assignEndDate: {type: Date},
}
);
I'm running my query from employee-project table which is my main table.
What I wanna do is to match a string with with employeeID and employeeName(employee table) and also with projectName(project table).
What I'm doing right now (which is wrong)
async rpSearch(data): Promise<any> {
try {
const result = await MongooseEmployeeProject.find()
.populate({
path: 'empID',
select: 'employeeID employeeName designation region comments resourceManager',
match:{
type:{data}
}
})
.populate({
path: 'projectID',
select: 'projectName tech startDate endDate customerID'
match:{
type:{data}
})
please guide me
First, path must be the field name of the schema. you set path with "employeeID" but "empID" is correct as employeeProjectSchema's field name.
Second, you set match but there is no type field in your employeeSchema and employeeProjectSchema neither. so you have to remove match.
async rpSearch(data): Promise<any> {
try {
const result = await MongooseEmployeeProject.find()
.populate({
path: 'empID',
select: 'employeeID employeeName designation region comments resourceManager'
})
.populate({
path: 'projectID',
select: 'projectName tech startDate endDate customerID'
})

Id is created for every nested objects in documents of a collection in mongodb via mongoose

I have a user schema. While saving document, for every nested object (quizHistory,record & responses) in document, mongoose add _id field automatically. For ref- quizHistory path
const userSchema = new Schema({
firstName: { type: String, required: true ,trim:true},
lastName:{ type: String, required: true ,trim:true},
email: { type: String, unique: true, required: true },
isUser: { type: Boolean, default: true },
password: String,
quizHistory: [{
quizId: { type: Schema.Types.ObjectId, ref: 'Quiz' },
record: [{
recordId:{ type: Number},
startTime: { type: Date },
responses: [{
quesId: { type: Schema.Types.ObjectId, ref: 'Question' },
answers: [Number]
}],
score: Number
}],
avgScore: Number
}]
})
Mongoose create virtual id by default(guide id).
Add this line to your schema.
_id : {id:false}

Mongoose delete nested subdocuments and documents

I have:
let userSchema = mongoose.Schema({
email: {type: String, required: true, unique: true},
passwordHash: {type: String, required: true},
fullName: {type: String, required: true},
salt: {type: String, required: true},
ads: [{type: ObjectId, ref: 'Ad'}],
roles: [{type: String}]
}
let adSchema = mongoose.Schema({
author: {type: ObjectId, ref: 'User'},
title: {type: String, required: true},
category: {type: ObjectId, ref: 'Category', required: true},
town: {type: ObjectId, ref: 'Town', required: true},
}
);
let categorySchema = mongoose.Schema({
name: {type: String, required: true, unique: true},
ads: [{type: ObjectId, ref: 'Ad'}]
}
);
let townSchema = mongoose.Schema({
name: {type: String, required: true, unique: true},
ads: [{type: ObjectId, ref: 'Ad'}]
}
);
I want to find for example town by id and remove all ads in it(and ofcourse to remove the ads from their categories and authors).How can i do that?
I would suggest bulk getting the array of object Ids and using it like this:
Ad.remove({_id: {$in: Ad_ids_array}}, function(){...}); // and so on
You can add a pre-remove hook in the ad schema definition like this:
adSchema.pre('remove', function(next) {
let lethis = this;
// Pull ad out of all the Category docs that reference the removed ad.
this.model('Category').update({}, { $pull: {ads: lethis._id}}, { safe: true }, next);
// Pull ad out of all the User docs that reference the removed ad.
this.model('User').update({}, { $pull: {ads: lethis._id}}, { safe: true }, next);
});
This will remove the ad from the categories and users that have it in their ads array.

.where() by populated fields

I want to find the closest workers by his location which have a specific skill.
Location schema:
var schema = Schema({
name: String,
type: String, // home | latest
user: {type: Schema.Types.ObjectId, ref: 'User'},
address: String,
position: {
type: {type: String, default: 'Point'},
coordinates: [Number]
},
status: String // active | inactive
}, {collection: 'locations'});
Worker schema:
var schema = Schema({
username: String,
password: String,
firstName: {type: String, default: ''},
middleName: {type: String, default: ''},
lastName: {type: String, default: ''},
role: {type: String, default: 'user'}, // admin | user | worker
skills: [{
object: {type: Schema.Types.ObjectId, ref: 'Skill'},
slug: String, // Should remove in the future
ratePerHour: Number,
status: {type: String, default: 'active'} // active | inactive
}],
locations: [{type: Schema.Types.ObjectId, ref: 'Location'}]
}, {collection: 'users'});
Skill schema:
var schema = Schema({
name: String,
slug: String,
users: [{type: Schema.Types.ObjectId, ref: 'User'}],
isFeatured: Boolean,
minRatePerHour: Number,
maxRatePerHour: Number,
status: String // active | inactive | deleted
}, {collection: 'skills'});
Bellow is my query but .where() does not work with populated field.
Location
.find({
'position': {
$near: {
$geometry: {type: 'Point', coordinates: [lat, lng]},
$minDistance: 0,
$maxDistance: 20000
}
}
})
.populate('user')
.deepPopulate('user.skills.object')
.where({'user.skills': {$elemMatch: {'object.slug': 'cleaning'}}})
.limit(5)
.exec(callback);
Am I doing wrong with these schemas? Should I use embed document rather than ID reference?
Is there any way else to query?
You have to use special properties for populate as described here: Query conditions and other options
So I think you can get your results with something like this:
Location
.find({
'position': {
$near: {
$geometry: {
type: 'Point',
coordinates: [lat, lng]
},
$minDistance: 0,
$maxDistance: 20000
}
}
})
.populate({
path: 'user',
match: {
'skills': {
$elemMatch: {
'object.slug': 'cleaning'
}
}
},
options: {
limit: 5
}
})
.deepPopulate('user.skills.object')
.exec(callback);
Not tested, keep it only as example.