I'm doing a test on a project using Jest.
This is the code for testing:
describe("POST /", () => {
let token;
let title;
let genre;
let dailyRentalRate;
const exec = async () => {
genre = await new Genre({
name: "abcde",
}).save();
return await request(server)
.post(config.get("URI") + "/movies")
.set("x-auth-token", token)
.send({ title, genre, numberInStock: 1, dailyRentalRate });
};
beforeEach(() => {
token = new User().generateAuthToken();
title = "abcdefg";
dailyRentalRate = 4.2;
});
it("should save the movie if it is valid", async () => {
const res = await exec();
console.log(genre);
console.log(res.body.error.details);
// const movie = await Movie.find({ title });
// expect(res.status).toBe(StatusCodes.OK);
// expect(movie).not.toBeNull();
});
});
The models are following:
Genre:
const mongoose = require("mongoose");
const genreSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minLength: 5,
maxLenght: 50,
},
});
const Genre = mongoose.model("Genre", genreSchema);
module.exports = { Genre, genreSchema };
Movie:
const mongoose = require("mongoose");
const { genreSchema } = require("./genre");
const Movie = mongoose.model(
"Movie",
new mongoose.Schema({
title: {
type: String,
required: true,
trim: true,
minlength: 2,
maxlength: 255,
},
genre: {
type: genreSchema,
required: true,
},
numberInStock: {
type: Number,
min: 0,
max: 255,
required: true,
},
dailyRentalRate: {
type: Number,
},
})
);
module.exports = { Movie };
When I test this suite, I receive the following error:
Why am I receiving this error and how to solve it?
Related
Hey I'm trying to build dashboard for calculate my medicine supplier total outstanding using nextjs.
*below *is my **createPurchase **api.
`
import PurchaseOrder from '../../models/PurchaseOrder'
import Supplier from '../../models/Supplier'
import connectDB from '../../middleware/mongoose';
import Medicine from '../../models/Medicine';
const handler = async (req, res) => {
if (req.method === 'POST') {
const medicines = [];
let totalOrderAmount = 0;
let totalPaybleGst = 0;
req.body.medicines.forEach(async medicine => {
let medicineOne = await Medicine.findById(medicine.medicine)
let newQuantity = parseInt(medicineOne.quantity) + parseInt(medicine.quantity)
const filter = { _id: medicine.medicine };
const update = { quantity: newQuantity };
await Medicine.findByIdAndUpdate(filter, update);
let newmedi = {
name: medicine.name,
company: medicine.company,
medicine: medicineOne,
quantity: newQuantity,
pack_detail: medicine.pack_detail,
category: medicine.category,
batch: medicine.batch,
mrp: medicine.mrp,
rate: medicine.rate,
gst: medicine.gst,
totalAmount: medicine.totalAmount,
expiryDate: medicine.expiryDate
}
totalOrderAmount += medicine.totalAmount;
totalPaybleGst += medicine.gst * medicine.rate * medicine.quantity * 0.01;
medicines.push(newmedi);
})
const paidAmount = req.body.paidAmount
const supplierBeforeUpdate = await Supplier.findById(req.body.supplier);
const newOustanding = supplierBeforeUpdate.totalOutstanding + totalPaybleGst + totalOrderAmount - paidAmount;
const filter = { _id: req.body.supplier };
const update = { totalOutstanding: newOustanding };
await Supplier.findOneAndUpdate(filter, update);
const supplierAffterUpdate = await Supplier.findById(req.body.supplier);
const purchaseOrder = await PurchaseOrder.create({
supplier: supplierAffterUpdate,
createdBy: req.body.createdBy,
medicines: medicines,
paybleGst: totalPaybleGst,
totalAmount: totalOrderAmount,
grandTotal: totalPaybleGst + totalOrderAmount,
paidAmount: paidAmount
})
res.status(200).json({ success: true, purchaseOrder: purchaseOrder })
}
else {
res.status(400).json({ error: "This method is not allowed" })
}
}
export default connectDB(handler);
`
this is my purchaseOrder Schema
`
const mongoose = require('mongoose');
const { Schema, model, models } = mongoose;
const medicinePurchaseSchema = new Schema({
name: { type: String, required: true },
company: { type: String, required: true },
medicine: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Medicine'
},
quantity: { type: Number, required: true },
pack_detail: { type: String, required: true },
batch: { type: String, required: true },
mrp: { type: Number, required: true },
rate: { type: Number, required: true },
gst: { type: Number, required: true },
totalAmount: { type: Number, required: true },
expiryDate: { type: Date, required: true }
});
const purchaseOrderSchema = new Schema({
supplier: { type: Object, required: true},
createdBy: { type: String, required: true },
medicines: [medicinePurchaseSchema],
paybleGst: { type: Number, required: true },
totalAmount: { type: Number, required: true },
paidAmount: { type: Number, required: true },
grandTotal: { type: Number, required: true }
}, { timestamps: true })
const PurchaseOrder = models.PurchaseOrder || model('PurchaseOrder', purchaseOrderSchema);
export default PurchaseOrder;
`
`
const mongoose = require('mongoose');
const { Schema, model, models } = mongoose;
const medicineSchema = new Schema({
name: { type: String, required: true },
company: {type: String, required: true},
pack_detail: {type: Number, required: true},
quantity: { type: Number, required: true },
category: { type: String, required: true },
status: { type: String, required: true }
}, { timestamps: true });
const Medicine = models.Medicine || model('Medicine', medicineSchema);
export default Medicine;
`
this is my Medicine schema
but problem is I got **totalOrderAmount **and **totalPayableGst **is **0 **in newOutstanding calculation, i think my newOutstanding calculation line is executing before updating my these variable in medicines.each function.
How can I fix this, im trying since 2 days but i didn't get any solution.
anyone have any solution.
That forEach method call will execute synchronously and doesn't await any promises. The callbacks do have await, but those affect only the async function they occur in, not the forEach method.
Instead of using forEach, use map, so that you get back the array of promises (as the async callbacks return promises). To make sure those promises resolve to something useful, have those callbacks return the newmedi. With Promise.all you can then know when all those promises resolved, and get all the medicine values to store in the medicines array, and only continue with the rest of the function when that is done:
// Not forEach, but map, and await all returned promises
const medicines = await Promise.all(req.body.medicines.map(async medicine => {
/* ...rest of your callback code... */
return newmedi; // Don't push, but return it
}));
I have been trying to follow the documentation to make a relationship between movies and categories (also among others that I will mention below, but starting with categories as an example).
Well, below I have the code of the parts of my code and the error response.
models/movie.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const {ObjectId} = mongoose.Schema;
const movieSchema = new Schema(
{
title: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
duration: {
type: String,
required: true,
},
rating: {
type: String,
required: true,
},
score: {
type: String,
required: true,
},
category: {
type: ObjectId,
ref: "Category"
},
description: {
type: String,
required: true,
},
director: [{
type: ObjectId,
ref: "Director"
}],
actor: [{
type: ObjectId,
ref: "Actor"
}],
studio: {
type: ObjectId,
ref: "Studio"
},
poster: {
type: String,
required: true,
},
trailer: {
type: String,
required: true,
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Movie", movieSchema);
models/category.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const {ObjectId} = Schema;
const categorySchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
movies: [
{
type: ObjectId,
ref: "Movie",
}
]
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Category", categorySchema);
controllers/movie.js
const Movie = require('../models/movie');
const Category = require('../models/category');
const Actor = require('../models/actor');
const Director = require('../models/director');
const Studio = require('../models/studio');
const create = async (req, res) => {
const content = req.body;
const category = await Category.findById(content._id);
const actor = await Actor.findById(content._id);
const director = await Director.findById(content._id);
const studio = await Studio.findById(content._id);
const newMovie = new Movie({
...content,
category,
actor,
director,
studio
});
const savedMovie = await newMovie.save();
category.movies = [...category.movies, savedMovie._id];
await category.save();
actor.movies = [...actor.movies, savedMovie._id];
await actor.save();
director.movies = [...director.movies, savedMovie._id];
await director.save();
studio.movies = [...studio.movies, savedMovie._id];
await studio.save();
res.status(201).json({
message: 'Movie created successfully',
movie: savedMovie
});
};
Now my post request
POST http://localhost:3000/api/v1/movies HTTP/1.1
Content-Type: application/json
{
"title": "The Matrixxx",
"year": 1999,
"duration": "136 min",
"rating": "R",
"score": "8.7",
"category": "6265ba915a8064456ac6231b",
"description": "A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.",
"director": ["626502e956cd00fe36692bf9"],
"actor": ["626501fc56cd00fe36692bf2"],
"studio": "626502ac56cd00fe36692bf7",
"poster": "https://images-na.ssl-images-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY#._V1_SX300.jpg",
"trailer": "https://www.youtube.com/embed/m8e-FF8MsqU"
}
Response
TypeError: Cannot read property 'movies' of null
at create (C:\Users\default\Desktop\streaming-backend\src\controllers\movie.js:26:36)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
Thanks for the answers :3
I think you forgot to use the necessary search fields. In theory, this code should look like this.
const category = await Category.findById(content.category);
const actor = await Actor.findById(content.actor[0]);
const director = await Director.findById(content.director[0]);
const studio = await Studio.findById(content.studio);
I have this in my backend:
ad = await Ad.find({'company': companyId}).populate('creator');
And when i console.log(ad) i get this:
[
{
connections: [],
status: 1,
_id: 6047c711b1f8cf1c98b2227c,
title: "DOTA: Dragon's Blood | Teaser | Netflix",
company: 6047c6fab1f8cf1c98b2227a,
video: 'uploads\\videos\\7802d640-810a-11eb-83c2-57e23ae6d491.mp4',
creator: {
companies: [Array],
ads: [Array],
_id: 6047c6e7b1f8cf1c98b22279,
name: 'test test',
email: 'test#live.com',
image: 'uploads\\images\\5f3ea850-810a-11eb-83c2-57e23ae6d491.jpeg',
password: '',
__v: 3
},
__v: 0
},
{
connections: [ 6047c745b1f8cf1c98b22280, 6047c83bb1f8cf1c98b22286 ],
status: 1,
_id: 6047c72cb1f8cf1c98b2227f,
title: 'Diretide 2020',
company: 6047c6fab1f8cf1c98b2227a,
video: 'uploads\\videos\\87a97d60-810a-11eb-83c2-57e23ae6d491.mp4',
creator: {
companies: [Array],
ads: [Array],
_id: 6047c6e7b1f8cf1c98b22279,
name: 'test test',
email: 'test#live.com',
image: 'uploads\\images\\5f3ea850-810a-11eb-83c2-57e23ae6d491.jpeg',
password: '',
__v: 3
},
__v: 6
}
]
But when i try to console.log(ad.creator) or console.log(ad.creator.ads) im getting undefined error.. I need this becasue i want to pull some things from ad.creator.ads..
Do i miss something in my code?
I will try to be more specific i tried but i cant figure how to do this:
ad.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const adSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
video: { type: String, required: true },
company: { type: mongoose.Types.ObjectId, required: true, ref: 'Company' },
creator: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
connections: [{type: mongoose.Schema.ObjectId, ref: 'User'}],
status: {type: Number, default: '1'}
});
module.exports = mongoose.model('Ad', adSchema);
So i need here when i delete this company to also pull all companies from user..
This is user.js
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, minlength: 6 },
image: { type: String, required: true },
companies: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Company' }],
ads: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Ad' }]
});
userSchema.plugin(uniqueValidator);
module.exports = mongoose.model('User', userSchema);
process for deleting company in // i specified part with problem where need to pull ads from user for this:
const deleteCompany = async (req, res, next) => {
const companyId = req.params.cid;
let company;
let ad;
try {
company = await Company.findById(companyId).populate('creator');
ad = await Ad.find({'company': companyId}).populate('creator');
} catch (err) {
const error = new HttpError(
'backend_message13',
500
);
return next(error);
}
if (!company) {
const error = new HttpError('backend_message14', 404);
return next(error);
}
if (company.creator.id !== req.userData.userId) {
const error = new HttpError(
'backend_message15',
401
);
return next(error);
}
const imagePath = company.image;
try {
const sess = await mongoose.startSession();
sess.startTransaction();
await company.remove({ session: sess });
company.creator.companies.pull(company);
await company.creator.save({ session: sess });
// here is the path where is problem i also tried with ad[0]
ad.creator.pull(ad.creator.ads);
await ad.creator.save({ session: sess });
//
await Ad.deleteMany({'company': companyId});
await sess.commitTransaction();
} catch (err) {
const error = new HttpError(
err,
500
);
return next(error);
}
fs.unlink(imagePath, err => {
console.log(err);
});
ad.forEach(function (item) {
const videoPath = item.video;
const thumb = item.video.replace("uploads\\videos\\","uploads\\videos\\thumb\\").replace(".mp4", "_screenshot.jpeg");
fs.unlink(videoPath, err => {
console.log(err);
});
fs.unlink(thumb, err => {
console.log(err);
});
});
res.status(200).json({ message: 'backend_message17' });
};
Thanks for help :)
append lean() mean on populate and then see
ad = await Ad.find({'company': companyId}).populate('creator').lean();
The query Ad.find() returns an array - but your code tried to access it as an object:
ad = await Ad.find({'company': companyId}).populate('creator');
console.log(ad.creator)
ad.creator actually is an undefined
Use an index to access required array element:
ad = await Ad.find({'company': companyId}).populate('creator');
console.log(ad[0].creator)
Or switch to Ad.findOne()
I am building ecommerce website using MERN stack. And I am getting error while testing using Postman.
backend/controllers/user.js
const User = require("../models/user");
const Order = require("../models/order");
exports.userPurchaseList = (req, res) => {
Order.find({ user: req.profile._id })
.populate("user", "_id name")
.exec((err, order) => {
if (err) {
return res.status(400).json({
error: "No Order in this account",
});
}
return res.json(order);
});
};
backend/models/Order.js
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const ProductCartSchema = new mongoose.Schema({
product: {
type: ObjectId,
ref: "Product",
},
name: String,
count: Number,
price: Number,
});
const ProductCart = mongoose.model("ProductCart", ProductCartSchema);
const OrderSchema = new mongoose.Schema(
{
products: [ProductCartSchema],
transaction_id: {},
amount: { type: Number },
address: String,
status: {
type: String,
default: "Recieved",
enum: ["Cancelled", "Delivered", "Shipped", "Processing", "Recieved"],
},
updated: Date,
user: {
type: ObjectId,
ref: "User",
},
},
{ timestamps: true }
);
const Order = mongoose.model("Order", OrderSchema);
module.exports = { Order, ProductCart };
backend/models/User.js
const mongoose = require("mongoose");
const crypto = require("crypto");
const uuidv1 = require("uuid/v1");
var userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
maxlength: 32,
trim: true,
},
lastname: {
type: String,
maxlength: 32,
trim: true,
// required: false,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
userinfo: {
type: String,
trim: true,
},
encry_password: {
type: String,
required: true,
},
salt: String,
role: {
type: Number,
default: 0,
},
purchases: {
type: Array,
default: [],
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
backend/routes/user.js
router.get(
"/orders/user/:userId",
isSignedIn,
isAuthenticated,
userPurchaseList
);
Error:-
TypeError: Order.find is not a function
at exports.userPurchaseList (C:\Users\Rahul\MernBootcamp\projbackend\controllers\user.js:47:9)
TESTING this route using POSTMAN.
You have exported an object so in your backend/controllers/user.js
you could import it like so from destructuring from the object then the rest of your code would be okay
const {Order} = require("../models/order");
or
accessing it using the dot notation
when calling the find Function
//importing it at the top
const Order = require("../models/order");
exports.userPurchaseList = (req, res) => {
Order.Order.find({ user: req.profile._id })
.populate("user", "_id name")
.exec((err, order) => {
if (err) {
return res.status(400).json({
error: "No Order in this account",
});
}
return res.json(order);
});
};
I have a users model which includes a locationsSchema in it:
const locationSchema = require('./location.js');
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
token: {
type: String,
require: true,
},
locations: [locationSchema],
passwordDigest: String,
}, {
timestamps: true,
});
My locations model is :
const mongoose = require('mongoose');
const locationSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
city: {
type: String,
},
region: {
type: String,
},
country: {
type: String,
},
coords: {
lat: {
type: Number,
require: true
},
long: {
type: Number,
require: true
},
},
visited: {
type: Boolean,
require: true,
default: false,
},
comment: {
type: String,
},
}, {
timestamps: true,
});
and finally the create action in my controller for locations is:
const controller = require('lib/wiring/controller');
const models = require('app/models');
const User = models.user;
const Location = models.location;
const create = (req, res, next) => {
User.findById(req.body.user.id).then (function(user){
let location = Object.assign(req.body.location);
user.locations.push(location);
return user.save();
})
.then(user => res.json({ user }))
.catch(err => next(err));
};
When I try to send a curl POST request to locations I get:
{"error":{"message":"this._schema.caster.cast is not a function","error":{}}}
console.logging user, user.locations, and locations just before the
user.locations.push(location);
line returns exactly what I'd expect. I'm fairly certain the error is stemming from the push function call. Any insight would be much appreciated.
your embedding location model
const locationSchema = require('./location.js');
so only you getting this error,
model can't be embedding schema only embedding
const locationSchema = require('./location.js'). schema;
so you try this