Reputation: 189
I have a user model and a car model. One user can have multiple cars. Here is the code -
let UserSchema = new Schema({
name:String,
age:String,
cars:[{
type:Schema.Types.ObjectId,
ref:"Car"
}]
})
const User = mongoose.model("User",UserSchema)
let CarSchema = new Schema({
make:String,
model:String,
owner:{
type:Schema.Types.ObjectId,
ref:"User"
}
})
const Car = mongoose.model("Car",CarSchema)
I am creating a user and a car model and storing the user id in the car and vice versa like this -
const user = new User({
_id: new mongoose.Types.ObjectId(),
name:'Raj',
age:50
})
user.save(function(err){
if(err){
console.log(err)
}
const car1 = new Car({
make:'Toyota',
model:'568',
owner:user._id
})
car1.save(function(err){
if(err){
console.log(err)
}
})
user.cars.push(car1)
user.save()
})
This works but if I need to perform an operation on one Car model,then it obviously wont reflect on the user car array and I have to do it separately i.e the models are not 'actually' linked. How can I make it so that performing an operation like delete on the Car model will automatically delete it from my user car array. Any help will be appreciated thanks.
Upvotes: 2
Views: 196
Reputation: 17858
There is no automatic way to delete cars from user when a car is removed. So you need to make operation on both the documents.
But there is a simpler way with only parent referencing. Don't keep car references in the user model and use virtual populate to populate cars from user.
Here are the steps:
1-) Change your user schema to setup virtual populate:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
let UserSchema = new Schema(
{
name: String,
age: Number,
},
{
toJSON: { virtuals: true },
}
);
UserSchema.virtual("cars", {
ref: "Car",
localField: "_id",
foreignField: "owner",
});
const User = mongoose.model("User", UserSchema);
Note that I removed the cars field, added toJSON: { virtuals: true }
option in the schema, set up virtual. (also modified age type as Number).
2-) Now we can create a user and car like this:
router.post("/users", async (req, res) => {
const user = new User({ name: "Raj", age: 50 });
try {
await user.save();
const car1 = new Car({
make: "Toyota",
model: "568",
owner: user._id,
});
await car1.save();
res.send("User and car saved");
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
As you see we needed 2 db operation instead of 3 since we don't need to push the car to the user's cars and save.
3-) Now we can populate the cars from user using populate:
router.get("/users/:id", async (req, res) => {
try {
const user = await User.findById(req.params.id).populate("cars");
res.send(user);
} catch (err) {
console.log(err);
res.status(500).send("Something went wrong");
}
});
This will give output:
{
"_id": "5ea685a3f1a0b02db8aaffe2",
"name": "Raj",
"age": 50,
"__v": 0,
"cars": [
{
"_id": "5ea685a5f1a0b02db8aaffe3",
"make": "Toyota",
"model": "568",
"owner": "5ea685a3f1a0b02db8aaffe2",
"__v": 0
}
],
"id": "5ea685a3f1a0b02db8aaffe2"
}
Upvotes: 2