I am using mongoDB populate model and when I try to save the data inside the schema it throws an error:
message: 'Cast to ObjectId failed for value
this is my schema
jobSiteInformation: {
buildingName: String,
street: String,
city: String,
},
data: [{
ref: 'data',
type: Schema.Types.ObjectId,
required: true,
}],
phase schema is like this
const listSchema= new Schema({
name: String,
progress: Number,
list: [],
});
this phase schema is array inside phases which is the quite large and thats the reason I moved to populate model.
anyway this is my route and when I run this it throws the error I pasted above.
router.post('/', async (req, res, next) => {
const info= new List({
jobSiteInformation: req.body.jobSiteInformation,
});
try {
const install = req.body.list;
install.map((inst) => info.lists.push(inst));
const saved= await partial.save();
return res.status(201).json({
result: saved,
});
} catch (e) {
console.log(e);
return next(e);
}
});
I have tried to google but I cannot find the what I am looking for. I have read other posts too but cannot understand what I am doing wrong here.
Assuming mongoose model for phase schema is Phase
// import Phase from ../models/phase
router.post('/request/partial', async (req, res, next) => {
const partial = new PartialRequest({
jobSiteInformation: req.body.jobSiteInformation,
});
try {
const install = req.body.installations;
let savedPhases = await Phase.insertMany(install); // TODO: handle error case
savedPhases.map((inst) => partial.installations.push(inst["_id"]));
const savedPartials = await partial.save();
console.log(savedPartials);
return res.status(201).json({
result: savedPartials,
});
} catch (e) {
console.log(e);
return next(e);
}
});
Related
I have this collection Cart (cart schema) to delete and it is referenced with 2 other schemes, Meal and Customer (owner user, its schema is: User Schema).
How can I delete the cart by passing as req.params.id the user's id from the HTTP request?
Cart Schema
const mongoose = require('mongoose');
const idValidator = require('mongoose-id-validator');
const Schema = mongoose.Schema;
const cartItemSchema = new Schema ({
quantity: { type: Number, required: true },
itemId: { type: mongoose.Types.ObjectId, required: true, ref: 'Meal' }
});
const cartSchema = new Schema ({
cartItems : [
cartItemSchema
],
customer: { type: mongoose.Types.ObjectId, required: true, ref: 'User'}
});
cartSchema.plugin(idValidator);
module.exports = mongoose.model('Cart', cartSchema);
I created a function to delete the document, but it doesn't work, it returns the message: 'Deleted cart.', but isn't true, the document remains in collection.
const deleteCartByUserId = async (req, res, next) => {
const userId = req.params.uid;
let cart;
try {
cart = await Cart.find({ customer: userId });
} catch(err) {
const error = new HttpError('Something went wrong, could not delete cart.', 500);
return next(error);
}
if(!cart) {
const error = new HttpError('Could not find cart for this user id.', 404);
return next(error);
}
try {
Cart.deleteOne({ customer: userId });
} catch(err) {
console.log(err);
const error = new HttpError('Something went wrong, could not delete cart.', 500);
return next(error);
}
res.status(200).json({ message: 'Deleted cart.' });
};
So the porblem was that you missed an await before delete one function call.
Also I've changed some of youre code to make it cleaner:
const functionHandler = fn =>
(req, res, next) =>
Promise
.resolve(fn(req, res, next))
.catch(next);
const deleteCartByUserId = functionHandler(async (req, res) => {
const { params: { uid: userId } } = req;
const cart = await Cart.findOneAndDelete({ customer: userId })
if(!cart) {
throw new HttpError('Could not find cart for this user id.', 404);
}
res.status(200).json({ message: 'Deleted cart.' });
});
In your error handler middleware you can check for error type and if it's not HttpError use internal server error.
I'd like to make a query that moves ytbReqTb's data to ytbChannelTb.
This is my Schema(ytbReqTb)
const ytbReqTbSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
ytbChannel: String,
ytbSubscribe: Number,
ytbHits: Number
}
and this is my other Schema(ytbChannelTb).
{
const ytbChannelTbSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
ytbChannel: String,
ytbSubscribe: Number,
ytbHits: Number,
}
So I query like this and it works.
router.put('/recognize/:youtuber', async (req, res, next) => {
const ytbReq = await YtbReqTb.find({ 'ytbChannel' : req.params.youtuber });
await YtbReqTb.remove({ 'ytbChannel' : req.params.youtuber });
const ytbChannelTb = new YtbChannelTb({
_id: new mongoose.Types.ObjectId(),
ytbChannel: ytbReq[0].ytbChannel,
ytbSubscribe: ytbReq[0].ytbSubscribe,
ytbHits: ytbReq[0].ytbHits,
});
ytbChannelTb.save()
.then(result => {
res.status(201).json();
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
But it doesn't work without '[0]'. Is there a way to query without '[0]'?
If query can't take out '[0]', could you tell me why?
the result of find is a array, if you want result be an object so use findOne instead of find like this:
const ytbReq = await YtbReqTb.findOne({ 'ytbChannel' : req.params.youtuber });
I have been trying to access a collection that was dynamically created in the database through {$out: "Accepted"} in nodejs using mongoose. the collection was successfully created.
from the controller:
exports.accepted = async (req, res, next)=>{
await Pupil.aggregate([{$match: {status: "Accepted"}}, {$out: "Accepted" }])
**Accepted.find({}).then(result=>{
res.render('home/accepted', {results: result, pageTitle: 'accepted page'})
}).catch(error=>{
console.log(error)*emphasized text*
});**
}
I want to retrieve the documents in that 'Accepted' collection and render them to the ejs file.
the error message is:
Accepted.find({}).then(result=>{
^
ReferenceError: Accepted is not defined at exports.accepted...
can someone please help me out?
Thanks!
Welcome to StackOverflow #Jerevick
There are two possible cases here:
Case 1 - You don't need to write to a new collection
You just want to find documents of accepted pupils and render them in the EJS template, in which case:
A) You don't need to write your documents into a new collection, you can just get them from the result and pass them to your template.
exports.accepted = async (req, res, next) => {
try {
const result = await Pupil.aggregate([{ $match: { status: 'Accepted' } }]);
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
B) You don't even need the aggregation framework, you can just do a simple find:
exports.accepted = async (req, res, next) => {
try {
const result = await Pupil.find({ status: 'Accepted' });
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
Case 2 - you need to write to a new collection, and your example was just to simplify
If that's the case, it's important to emphasize the difference between mongoose and MongoDB. Mongoose is a wrapper around the native MongoDB driver to help with casting, and provide a nicer API.
When you add a new collection to the database using the $out stage, the mongoose isn't aware of it and it doesn't assign a model for it and has no idea what kind of data live there, in which case you would need to bypass mongoose and use the native MongoDB driver directly.
I highly advise against this approach, since you'd be giving up all the convenience mongoose provides, don't take this approach unless you really know what you're doing, there's probably a better solution than using the native driver directly.
exports.accepted = async (req, res, next) => {
try {
await Pupil.aggregate([{ $match: { status: 'Accepted' } }, { $out: 'Accepted' }]);
const acceptedCollection = mongoose.connection.collection('Accepted');
const result = await acceptedCollection.find({}).toArray();
res.render('home/accepted', { results: result, pageTitle: 'accepted page' });
} catch (err) {
console.log(err);
}
};
Here's a full reproduction script you can play with:
65209755.js
'use strict';
const mongoose = require('mongoose');
const { Schema } = mongoose;
const assert = require('assert');
run().catch(console.error);
async function run () {
await mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
});
await mongoose.connection.dropDatabase();
const studentSchema = new Schema({
name: String,
status: String
});
const User = mongoose.model('User', studentSchema);
await User.insertMany([
{ name: 'Hafez1', status: 'Accepted' },
{ name: 'Hafez2', status: 'Accepted' },
{ name: 'Hafez3', status: 'Accepted' },
{ name: 'Hafez4', status: 'Rejected' },
{ name: 'Hafez5', status: 'Rejected' }
]);
await User.aggregate([
{ $match: { status: 'Accepted' } },
{ $out: 'acceptedstudents' }
]);
const db = mongoose.connection;
const acceptedStudents = await db.collection('acceptedstudents').find({}).toArray();
assert.deepStrictEqual(
acceptedStudents.map(student => student.name),
['Hafez1', 'Hafez2', 'Hafez3']
);
console.log('All assertions passed.');
}
Output
$ node 65209755.js
All assertions passed.
I have an Order model that looks like this
const mongoose = require('mongoose');
const orderSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
products: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true }]
});
module.exports = mongoose.model('Order', orderSchema);
This is the OrderController:
exports.orders_create_order = (req, res, next) => {
console.log("======This is what we're sending to the endpoint==============================");
console.log(req.body);
console.log('====================================');
const order = new Order({
_id: mongoose.Types.ObjectId(),
products: req.body.products
});
order.save().then(result => {
console.log('====================================');
console.log("This is what is getting saved");
console.log(result);
console.log('====================================');
res.status(201).json({
message: "Order stored",
createdOrder: {
_id: result._id,
products: result.product
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
It takes an array of objects that I am sending from the a react frontend like so:
axios.post("http://ocalhost:4500/orders/", {"products":"[5e9e7edb4e0e5100041e3aa1, 5e9e85824e0e5100041e3aa4, 5e9e859d4e0e5100041e3aa6]"})
.then(res => {
console.log('=======This is the data we are getting from saving new wishlist at the frontend=============================');
console.log(res.data);
console.log('====================================');
})
.catch(err =>
console.log(`The error we're getting from the backend--->${err}`))
the error I am getting here is :
message: 'Cast to Array failed for value "[5e9e7edb4e0e5100041e3aa1, 5e9e85824e0e5100041e3aa4, 5e9e859d4e0e5100041e3aa6]" at path "products"',
Please tell me what am I doing wrong here?
You are tring to send products as string, it should be an array like this:
{
"products": [
"5e9e7edb4e0e5100041e3aa1",
"5e9e85824e0e5100041e3aa4",
"5e9e859d4e0e5100041e3aa6"
]
}
I'm trying to post a service json with nested array json objects relationships todos. When I do that, app shows me next error:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'find' of undefined
This is my model class:
const serviceSchema = new Schema({
name: String,
subject: String,
pricePerHour: Number,
relatedTodos:
[{type: mongoose.Schema.Types.ObjectId,
ref:'todos'}],
createdAt: Date,
updatedAt: Date
});
This is my post route:
app.post('/api/services', async (req, res) => {
const { name, subject, pricePerHour} = req.body;
let todos = await Service.findById(req.params.id).TODO.find({});
if (!todos) {
return res.status(404).json({
message: "todos couldn't be found"
});
}
const service = new Service({
name,
description,
pricePerHour,
relatedTodos
})
try {
let newService = await service.save();
res.status(201).send(newService);
} catch (err) {
if (err.name === 'MongoError') {
res.status(409).send(err.message);
}
res.status(500).send(err);
}
});
How can I'm doing wrong?