sails.jssails-mongo

Create method in sails makes a new record but return bad Request


I have this model called Services

/**
 * Services.js
 *
 * @description :: A model definition represents a database table/collection.
 * @docs        :: https://sailsjs.com/docs/concepts/models-and-orm/models
 */

module.exports = {

  attributes: {

    //  ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦  ╦╔═╗╔═╗
    //  ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗
    //  ╩  ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝
    nameService: {
      type: "string",
      required: true,
      description: "Full representation of the service's name.",
      example: "Details of this particular service offered by the studio"
    },
    creditCost: {
      type: "number",
      required: true,
      description: "The number of credits required for this service",
      example: 2
    },
    creditsEarned: {
      type: "number",
      defaultsTo:0,
      description: "The number of credits required for this service",
      example: 200
    },
    price: {
      type: 'number',
      required: true,
      description:"The original price of this service",
      example:1500
    },
    rating: {
      type: 'number',
      defaultsTo:0,
      min: 0,
      max: 5,
    },



    //  ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
    //  ║╣ ║║║╠╩╗║╣  ║║╚═╗
    //  ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝


    //  ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
    //  ╠═╣╚═╗╚═╗║ ║║  ║╠═╣ ║ ║║ ║║║║╚═╗
    //  ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝


    studioId:{
      model:"Studios"
    },
    bookedServices:{
      collection: 'BookedServices',
      via: 'serviceId'

    },


    timings:{
      collection: 'Timings',
      via: 'serviceId'
    }

  },

};

This is my action file that adds services.

For some reason, await Services.create is not working and as the serviceRecord is not defined it is returning this badRequest error. But when I shifted to using promises which is exec here, I see that the record is being created but the result which is the second parameter in the exec is also coming undefined.

As I had to push the studioId into the services, I had no choice but to include it in when making the record, although this is also showing badRequest, it is putting the record in the database.

It would be greatly appreciated if anyone can tell me what is the cause of the problem. I checked the types of the parameters I am putting into the Service model and they do match up, serviceName is string, creditCost and price are number.

/**
 * studiosControllers/services/addServices.js
 *
 * @description :: Login action for studios.
 * @help        :: See https://sailsjs.com/docs/concepts/actions
 */

module.exports = {
  friendlyName: "Add Services",

  description: "Studios adding services.",

  extendedDescription: `This action will do the part of adding services to the particular studio.`,

  inputs: {
    nameService: {
      type: "string",
      required: true,
      description: "Full representation of the service's name.",
      example: "We are a great studio that offer variety of services..."
    },
    creditCost: {
      type: "number",
      required: true,
      description: "The number of credits required for this service",
      example: 2
    },

    price: {
      type: "number",
      required: true,
      description: "The original price of this service",
      example: 1500
    }
  },

  exits: {
    success: {
      description: "New service was created successfully."
    },

    invalid: {
      responseType: "badRequest",
      description: "Some of the provided details are invalid.",
      extendedDescription:
        "If this request was sent from a graphical user interface, the request " +
        "parameters should have been validated/coerced _before_ they were sent."
    }
  },

  fn: async function(inputs, exits) {
    var { nameService, creditCost, price } = inputs;
    console.log(typeof nameService);
    console.log(typeof creditCost);
    console.log(typeof price);

    let newNameService = nameService.toLowerCase();
    var serviceRecord;

    Services.create({ nameService: newNameService, creditCost:creditCost, price:price,studioId:this.req.params.studioId }).exec(
      function(err,result) {
        if (err) {
          return this.res.send(err);
        }
        console.log(err);
        serviceRecord=result;
        console.log(serviceRecord);
      }
    );

    // try {
    //   serviceRecord = await Services.create({
    //     nameService: newNameService,
    //     creditCost,
    //     price
    //   });
    //   sails.log.info(serviceRecord);
    // } catch (err) {
    //   switch (err.name) {
    //     case "UsageError":
    //       return this.res.badRequest(err);
    //     default:
    //       throw err;
    //   }
    // }

    // If there was info mismatch, throw invalid error
    if (!serviceRecord) {
      throw "invalid";
    }

    let id = this.req.studioId;
    var studioRecord;

    try {
      studioRecord = await Studios.findOne({
        id
      });
      studioRecord.services.add(serviceRecord);
      studioRecord.save();
      return exits.success({
        message: "Service added successfully to the studio",
        data: serviceRecord
      });
    } catch (err) {
      switch (err.name) {
        case "UsageError":
          return this.res.badRequest(err);
        default:
          throw err;
      }
    }
  }
};

EDIT:-

This is another api called Timings and even this has the same problem. Is it something that I have done wrong with the process of creating a new document or something else?

Timings Model:-

/**
 * Timings.js
 *
 * @description :: A model definition represents a database table/collection.
 * @docs        :: https://sailsjs.com/docs/concepts/models-and-orm/models
 */

module.exports = {
  attributes: {
    //  ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦  ╦╔═╗╔═╗
    //  ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗
    //  ╩  ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝


    eventInTime: {
      type: "ref",
      required: true,
      columnType: "datetime",
      description: "The date of the event starting",
      extendedDescription: `To store a date, make a date object with 
      'let date=new Date(year, month, day, hours, minutes, seconds, milliseconds)' 
      and then stringify it with 'JSON.stringify(date)' and then store it in the database 

      Send in "stringify" ed version of the date object to this input
      `
    },
    eventOutTime: {
      type: "ref",
      required: true,
      columnType: "datetime",
      description: "The date of the event ending",
      extendedDescription: `To store a date, make a date object with 
      'let date=new Date(year, month, day, hours, minutes, seconds, milliseconds)' 
      and then stringify it with 'JSON.stringify(date)' and then store it in the database 

      Send in "stringify" ed version of the date object to this input
      `
    },
    numberOfSlotsAvailable: {
      type: "number",
      required: true,
      description: "The number of available slots",
      example: 15
    },


    //  ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗
    //  ║╣ ║║║╠╩╗║╣  ║║╚═╗
    //  ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝

    //  ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗
    //  ╠═╣╚═╗╚═╗║ ║║  ║╠═╣ ║ ║║ ║║║║╚═╗
    //  ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝

    bookedServicesId:{
      model:"BookedServices"
    },
    serviceId:{
      model:"Services"
    }
  }
};

Timing controller:-

/**
 timingsController/entrance/add-timings.js
 *
 * @description :: Action for adding timings to services.
 * @help        :: See https://sailsjs.com/docs/concepts/actions
 * FIXME: 
 */

module.exports = {
  friendlyName: "Add timings",

  description: "Studi`os adding timings for their services.",

  extendedDescription: `This action will do the part of adding timings to the particular service.`,

  inputs: {
    eventInTime: {
      type: "ref",
      required: true,
      columnType: "datetime",
      description: "The date of the event starting",
      extendedDescription: `To store a date, make a date object with 
      'let date=new Date(year, month, day, hours, minutes, seconds, milliseconds)' 
      and then stringify it with 'JSON.stringify(date)' and then store it in the database 

      Send in "stringify" ed version of the date object to this input
      `
    },
    eventOutTime: {
      type: "ref",
      required: true,
      columnType: "datetime",
      description: "The date of the event ending",
      extendedDescription: `To store a date, make a date object with 
      'let date=new Date(year, month, day, hours, minutes, seconds, milliseconds)' 
      and then stringify it with 'JSON.stringify(date)' and then store it in the database 

      Send in "stringify" ed version of the date object to this input
      `
    },
    numberOfSlotsAvailable: {
      type: "number",
      required: true,
      description: "The number of available slots",
      example: 15
    }
  },

  exits: {
    success: {
      description: "New timing record was created successfully."
    },

    invalid: {
      responseType: "badRequest",
      description: "Some of the provided details are invalid.",
      extendedDescription:
        "If this request was sent from a graphical user interface, the request " +
        "parameters should have been validated/coerced _before_ they were sent."
    }
  },

  fn: async function(inputs, exits) {
    var moment = require("moment");

    var { eventInTime,eventOutTime, numberOfSlotsAvailable } = inputs;


    // var eventInTimeMix = moment(eventInTime);
    // var eventInTimeDate = eventInTimeMix.utc().format("DD-MM-YYYY HH:mm a");
    // console.log(`This is eventInTimeMix: ${eventInTimeMix}`)
    // console.log(`This is eventInTimeDate: ${eventInTimeDate}`)

    // var eventOutTimeMix = moment(eventOutTime);
    // var eventOutTimeDate = eventOutTimeMix.utc().format("DD-MM-YYYY HH:mm a");



    var timingRecord;
    let serviceId = this.req.params.serviceId;
    console.log(serviceId)

  //   timingRecord=await Timings.create({
  //     eventInTimeDate,
  //     eventOutTimeDate,
  //     numberOfSlotsAvailable,
  //     serviceId
  //   }).fetch()

  // console.log(timingRecord)

    Timings.create({eventInTime,
      eventOutTime,
      numberOfSlotsAvailable,
      serviceId})

    .exec(function(err, result) {
      // if (err) {
      //   return this.res.send({err});
      // }
      // return this.res.status(200).send({ message: "Service added successfully" });
      console.log(`This is the error ${err}`);
      console.log(`This is the result ${result}`);

    });

    // try {
    //  timingRecord=await Timings.create({
    //   eventInTimeDate,
    //   eventOutTimeDate,
    //   numberOfSlotsAvailable,
    //   serviceId
    // })
    // } catch (err) {
    //   switch (err.name) {
    //     case "UsageError":
    //       return this.res.badRequest(err);
    //     default:
    //       throw err;
    //   }
    // }

    //FIXME: Remove the ommenting from the below line for verification

    // If there was info mismatch, throw invalid error
    if (!timingRecord) {
      throw "invalid";
    }



  }
};

In the controller, the console log statements of error and result are returning undefined for some reason.

What can I do to fix this? Any help is greatly appreciated.


Solution

  • As mentioned in the documentation for Waterline's create method, if you want a copy of the newly created record you need to either chain the .fetch() method or .meta({ fetch: true })

    Something like the following should do it:

    let serviceRecord = await Services.create({
      nameService: newNameService,
      creditCost,
      price
    }).fetch();
    sails.log.info(serviceRecord);