How to insert an array of ids with create function in node

111 views Asked by At

I Have defined this mongoose schema in node

`const bookingSchema = new mongoose.Schema({
  tour: [
    {
      type: mongoose.Schema.ObjectId,
      ref: 'Tour',
      required: [true, 'Booking must belong to Tours!'],
    },
  ],
  user: {
    type: mongoose.Schema.ObjectId,
    ref: 'User',
    required: [true, 'Booking must belong to User!'],
  },
  price: {
    type: Number,
    required: [true, 'Booking must have a price'],
  },
  createdAt: {
    type: Date,
    default: Date.now(),
  },
  paid: {
    type: Boolean,
    default: true,
  },
});
bookingSchema.pre(/^find/, function (next) {
  this.populate('user').populate({
    path: 'tour',
    select: 'name',
  });`your text`
});

Then when i try to create a booking i use the create function 
await Booking.create({ tour, user, price });`

the tour param is an array of ids

but i get this error "Booking validation failed: tour.0: Cast to [ObjectId] failed for value "["5c88fa8cf4afda39709c295a,5c88fa8cf4afda39709c2951"]" (type string) at path "tour.0" I can do it with only one tour if the tour property wasnt an array of objects. My main issue is that a booking can be related to many tour objects in my database *edit after some modifications the error become "Unexpected token u in JSON at position 0"

My front end code(angular) is this. I am making a get request to my backend(node)

createBookingCheckout(params: any): Observable<any> {
    console.log('serv');
    return this.http.get<any>(`${CREATE_BOOKING_CHECKOUT}`, {
      params,
      withCredentials: true,
    });
  }

So i pass the ids as query param

And this is the backend where i am trying to create the booking

exports.createBookingCheckout = catchAsync(async (req, res, next) => {
  const { order, tour: strTour } = req.query;
  const user = req.user._id;
  const parsedOrder = JSON.parse(order);
  const tour = JSON.parse(strTour);
  console.log(tour);
  // const tours = await tour.forEach((id) => {
  //   Tour.find({ id });
  // });
  // console.log(tours);

  let price = 0;
  parsedOrder.forEach(
    (obj) => (price = price + obj.price_data.unit_amount * obj.quantity)
  );
  if (!parsedOrder && !user) return next();
  await Booking.create({ tour, user, price });
  res.redirect(req.originalUrl.split('?')[0]);
  res.status(200).json({
    status: 'success',
  });
});
1

There are 1 answers

6
Hicham Mounadi On

I think the quick solution to this is that whenever you are going to add more than a tour you should create an array push all tours IDs to the array and then add the tourArray to the new Booking that you are going to create, and when you are going to update an existing Booking, you should repeat the process.

When you are going to create a new Booking document.

Scenario 1 : with one Tour

  • You just pass the id of the tour {always check if the tour exist}, that's obvious and simple, at the same time mongo is going to create a table referring to the model as Tour is defined as many within your Booking model

Scenario 2 : with more than one Tour

  • You need to define all the Tour's IDs in an array within the body
{
    "tour": [ "id-1", "id-2", ...]
}

Updating a Booking

say that you are going to add a new Tour to an existing Booking,

Booking.findByIdAndUpdate(
        {_id: id},
        {
         // ! here all your other data

            $push: {tour: new_tour}
        },
// this is just to return the updated booking
        {new: true, runValidators: true}
}

=> the operator $push in mongoose is what you need to push into the existing array or tour that's already in your existing Booking The new_tour is coming from your req.body

as for sure in some cases you are going to delete a Tour ID from a Booking,

=> in that case you are going to use the operator $pull