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.
Related
I'm making a Forum application with my first Node Express Mongo API. Posts have an array of comments, and I am trying to delete a comment, based in it's id.
My method returns without errors, but the comment is never deleted.
Deleting method:
export const deleteComment = async (req, res) => {
const commentId = req.body._id
const post = await Post.findById(req.params.id)
const _id = post.id
try {
await Post.updateOne(
{ _id },
{
$pull:
{
comments: { _id: commentId }
}
}
)
res.status(200).json({ message: 'Success' })
} catch (error) {
res.status(400).json({ error: error.message })
}
}
The model looks like the following:
Previously, when using the updateOne method, it for some reason had issues finding the id of the model to update, but I have now used the same formula as before, so I don't see that as being an issue.
Any guesses of what I can do to fix this?
this is my route handler
router.get("/get-bookmarks", async (req, res) => {
const bookmarks = await Post.find({ _id: { $all: req.body.idList } });
if (!bookmarks) return res.status(404).send("No bookmarks yet");
return res.send(bookmarks);
});
this is the data to search using postman
{
"idList": ["60c07302f033f51f6c87c986","60c07399f033f51f6c87c989","60c0736ff033f51f6c87c988"]
}
You can do it with $in operator, like this:
Post.find({ _id: { $in: req.body.idList } });
Here is the working example: https://mongoplayground.net/p/gs-nuaB-_Ux
GoodDay Experts,
I've tried following code but it did not work, and it gives me null value.. maybe my routes are wrong but basically it works the way on other routes... and here is my backend for delete case: manage.js/actions
export const removeRecipient = (payload) => async (dispatch) => {
try {
const res = await axios.delete(
`${_config.MAT_URL}/api/1/customer/delete`,
payload
);
dispatch({
type: DELETE_CUSTOMER,
payload: res.data,
});
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { err },
});
}
};
and for my routes which is the mongoose query for findOneAndDelete, under customer.js :
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: req.params.id }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
And for the front end im using "AiOutlineDelete" which was coded as :
const handleDelete = (id) => {
console.log('delete')
removeRecipient(id)
}
<a
id={`delete-${rowIndex}`}
className="anchor-action-delete"
href="#foo"
onClick={(e) => {
e.preventDefault();
handleDelete(row);
}}>
thanks have a great day
There are 2 problems in your code:
req.params.id is meant for urls of the form /delete/:id which is obviously not your route, you should change it to req.query.id instead which matches query parameters in the url such as /delete?id=123.
The default type of _id is ObjectId, under the assumption you did not change this you need to cast your req.query.id which is type string to ObjectId.
It looks like you're using mongoose so here's mongoose syntax:
const mongoose = require("mongoose");
router.delete("/delete", (req, res) => {
Customer.findOneAndDelete({ _id: new mongoose.Types.ObjectId(req.query.id) }, (err, Customer) => {
if (!err) {
res.json({ msg: "customer deleted", deleted: Customer });
} else {
console.log("Error removing :" + err);
}
});
});
For nodejs native Mongo package:
import {ObjectId} from "mongodb";
...
new ObjectId(req.query.id)
I dont see you sent the id to the backend but you are trying to retrieve it from req.params.id try passing the id like "delete/:id" at the end of the link and specify this in the routes aswell.
if that doesnt fix try the below code this for routes
if nothing works check this, In the component you need to send the id(object id) but i see "row" what is the value of row? if the row value is not the id in the database then it wont delete. if this your issue try inspecting the code by keeping breakpoints or write a console.log() to check the value of "row" .
try {
const removedProject = await Customer.remove({
_id: req.params.id
})
res.json(removedProject)
} catch (err) {
res.json({
message: err
})
}
I have a Schema system with nested schemas to create a one to many relationship.
User Schema
const expenseSchema = new Schema({
expense: String,
value: Number
});
const budgetSchema = new Schema({
earnings: Number,
expenses: [expenseSchema]
});
const userSchema = new Schema({
username: String,
name: String,
googleId: String,
budget: [budgetSchema]
});
I am trying to push a value to these nested schemas but been having some trouble. Note The req.user value is of authenticated users through Passport authentication
This is my attempt to add data into the budget schema's earning property. The weird thing is that when I log the user after the post request it shows undefined.
router.post("/", (req, res) => {
User.findOneAndUpdate(req.user, {
$push: {
budget: {
earnings: req.body.earning
}
}
});
console.log(req.user);
});
Vue form
submitBudget() {
const expenses = this.mergeKeyAndValue();
axios
.post("http://localhost:3000/budget", {
earning: this.earnings,
expenses
})
.then(response => {
console.log(response.data);
})
.catch(e => {
console.error(e);
});
}
router.post("/", (req, res) => {
User.findOneAndUpdate(req.user,
{$push:{
budget: {
earnings: req.body.earning
}
}
}
)
console.log(req.user);
})
In here, you are not providing a callback function to User.findOneAndUpdate() and without such function, all you're doing is querying the database without saving anything.
Taken from Mongoose docs about Model.findOneAndUpdate()
A.findOneAndUpdate(conditions, update, options, callback) // executes
A.findOneAndUpdate(conditions, update, options) // returns Query
A.findOneAndUpdate(conditions, update, callback) // executes
A.findOneAndUpdate(conditions, update) // returns Query -> This is what you are doing right now.
A.findOneAndUpdate() // returns Query
Additionally, your syntax is incorrect that's probably why you're getting undefined. It should be Users.findOneAndUpdate({ username: req.user },..... or wherever your req.user username key the request object holds is stored.
You can rewrite the whole function using async/await in the following way:
router.post("/", async (req, res) => {
const update = await User.findOneAndUpdate(
{ username: req.user.username },
{
$push: {
budget: {
earnings: req.body.earning
}
}
}
)
console.log(update);
});
I don't have an easy way to test the $push update so I'm going to assume you know what you are doing but the rest should be as described.
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);
}
});