Sushmit Chakraborty
Sushmit Chakraborty

Reputation: 189

Mongoose one to many relationship issue

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

Answers (1)

SuleymanSah
SuleymanSah

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

Related Questions