Mongodb,express find data by _id with multiple condition - javascript

My code is shown below:
PostCategory.find({categoryid:category._id.str},function(err,postcategories){
if(err) return next(err);
Post.find({_id:postcategories.postid},function(err,posts){
if(err) return next(err);
return res.render(__dirname + "/views/categorydetail", {
title: 'İletişim',
stylesheet: 'contact'
});
});
});
I want to find all post which _id is in postcategories.postid. My postcategories returns me list. Here is my postcategories model:
module.exports = function(){
var PostCategorySchema = new mongoose.Schema({
postid:String,
categoryid:String,
createddate:{ type: Date, default: Date.now }
});
mongoose.model("PostCategory",PostCategorySchema);
};
Any idea?

First of all, your Mongoose model needs to be something like that:
var PostCategorySchema = new mongoose.Schema({
postid: { type: mongoose.Schema.Types.ObjectId, ref: 'Post' },
categoryid: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
createddate:{ type: Date, default: Date.now }
});
mongoose.model("PostCategory", PostCategorySchema);
The ref option is what tells Mongoose which model to use during population, in our case the Post model (same thing for categoryid field).
After that, your request becomes really simple:
var query = PostCategory.find({ categoryid: category._id });
query.populate('postid');
query.exec(function (err, postcategories) {
if (err) return next(err);
// res.render('......');
});
For more information, you should read the Mongoose Query Population documentation.
EDIT:
So, if you have more than one post for a postcategory, update the model to:
var PostCategorySchema = new mongoose.Schema({
postid: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }],
categoryid: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
createddate:{ type: Date, default: Date.now }
});

the simple way is :
PostCategory.find({categoryid:category._id.str},function(err,postcategories){
if(err) return next(err);
var ids = [];
_.each(postcategories, function(postCategory){
ids.push(postCategory.postid);
});
Post.find({_id : { $in : ids } },function(err,posts){
if(err) return next(err);
return res.render(__dirname + "/views/categorydetail", {
title: 'İletişim',
stylesheet: 'contact'
});
});
)};
In my example, i use underscoreJS to fetch postCategories List

Related

How to pull items from reference array based on condition in array?

I am working in creating a todo list and one of the action I want users to do is delete all completed todos in one click. I have my models here, and the code I have, I have been reading trying to figure it out, but can't find it anywhere. Thanks in advance.
User Model
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
todos: [{
type: mongoose.Types.ObjectId,
ref: 'Todo'
}]
});
Todo model:
const TodoSchema = new mongoose.Schema({
creator: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User',
},
content: {
type: String,
required: true,
},
completed: {
type: Boolean,
default: false
},
});
This is what I have now. I get a "Cast to ObjectId failed for value true at path todos.
router.delete('/delete/completed', auth, async (req, res) => {
try {
const userTodos = await User.update(
{'_id':req.user.id},
{ $pull: { 'todos': { 'completed': true } } },
{ multi: true }
);
if (!userTodos) {
return res.status(400).send('Server error');
}
return res.json({ userTodos });
//return res.json({msg: 'All completed removed'})
} catch (err) {
console.error(err.message);
return res.status(404).json({ msg: 'Something went wrong, try again' });
}
});
If you are (as it seems from your code) using mongoose, you could use mongoose's populate feature:
const userTodos = await User.find(
{'_id':req.user.id}).populate('todos', {
match: {completed: true}
});
please note, however, that you'll need to delete both the documents in the todos collection, AND the todo reference in the user's todos array. You may consider to remove one side of the reference, see the pros and cons of two-way referencing here

Mongoose does not populate

I am trying to populate one of my models but it does not work.
This is my Card schema:
const CardSchema = new mongoose.Schema({
text: {
type: String,
},
wrap: {
type: String,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
}
});
module.exports = mongoose.model('Card', CardSchema);
This is my controller:
exports.getCards = asyncHandler(async (req, res, next) => {
const cards = await Card.find({}).populate('user').exec();
res.status(200).json({
success: true,
count: cards.length,
data: cards,
});
});
It does return the cards but without any user field.
The user schema is exported as "User"
You have made a small mistake in defining the models while you referring the User Collections, remove the single quotes
The model definition should be as follows
const CardSchema = new mongoose.Schema({
text: {
type: String,
},
wrap: {
type: String,
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: User, // Replace 'User' with User
}
});
module.exports = mongoose.model('Card', CardSchema);

How can I update an index object array by id

I have the object array's ID and I want to update the info with information I already have on my backend.
My code deletes every array and creates a new one with the new info.
I want to access the array with the variable ID and then change it's values:
const ProdcutSchema = new mongoose.Schema({
name:{
type: String,
required: true
},
productDescription:{
type: String,
required: true
},
pricePerUnit:{
type: Number,
required: true
},
productAmmount:{
type:Number,
required: true
},
/*productImagePath:{
type:String,
required: true
}*/
});
const UserSchema = new mongoose.Schema({
name:{
type: String,
},
email:{
type: String,
},
password:{
type: String,
},
date:{
type: Date,
default: Date.now
},
products:[ProdcutSchema]
});
//Update products
router.put('/dashboard/:id', (req, res)=>{
const ID = req.params.id;
const {product_name, price_PerUnit, product_Description, product_Ammount} = req.body; //Get access to ajax data using body parser
if(!product_name || !price_PerUnit || !product_Description || !product_Ammount){
res.send('Please fill out all fields with valid content');
}else{
User.products.findOneAndUpdate(
{ _id : ID },
{ $set: { products: {
name :product_name,
productDescription : product_Description,
pricePerUnit : price_PerUnit,
productAmmount : product_Ammount
} } },
(err) => {
if (err) throw console.log('found errors');
console.log('no errors');
})
}
});
If you have ObjectId of that item you want to update, code should look like this:
User.products.findOneAndUpdate(
{ _id: ID, "products._id": <here goes id for an array element> },
{
$set: {
"products.$": {
name: product_name,
productDescription: product_Description,
pricePerUnit: price_PerUnit,
productAmmount: product_Ammount
}
}
},
err => {
if (err) throw console.log("found errors");
console.log("no errors");
}
);
Also u gotta be aware that u need to supply an specific ID of an array element for this kind of situation when you want to update subdocument.

Can't remove the user id from upvotes section

I've tried almost everything splice, pop, shift, remove but I can't remove the user id which simple means downvote the post.
Here is my code:
// #type POST
// #route /api/question/upvote/:id
// #desc route for upvoting answers to questions
// #access PRIVATE
router.post('/upvote/:id', passport.authenticate('jwt', {session:false}), (req, res)=> {
Profile.findOne({user: req.user.id})
.then(profile => {
Question.findById(req.params.id)
.then(question => {
if(question.upvotes.filter(upvote => upvote.user.toString() === req.user.id.toString()).length > 0){
return res.status(400).json({noUpvote : 'User is downvoted the question'});
}
question.upvotes.unshift({user : req.user.id});
question.save()
.then(question => res.json(question))
.catch(err => console.log('Error on saving the upvote user id :' + err));
})
.catch(err => console.log('Error on getting the question : ' + err));
})
.catch(err => console.log('Error on finding the user : ' + err));
});
There are the three models in my application:
//Load the Person Model
const Person = require('../../models/Person');
//Load the Profile Model
const Profile = require('../../models/Profile');
//Load the Questions Model
const Question = require('../../models/Questions');
So the upvote is in question model.
The Person model contains the registration and login information.
The Profile model contains the Person details. The Question model contains question, answer, comment, and upvotes.
Here is the question model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const QuestionSchema = new Schema({
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
textone: {
type: String,
required: true
},
texttwo: {
type: String,
required: true
},
name:{
type: String
},
upvotes: [{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
}
}],
answers:[{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
answer: {
type: String,
required: true
},
name:{
type: String
},
date: {
type: Date,
default: Date.now
}
}],
comments: [{
user : {
type: Schema.Types.ObjectId,
ref: 'myPerson'
},
name:{
type: String
},
text: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
}],
date: {
type:Date,
default: Date.now
}
});
module.exports = Questions = mongoose.model("myQuestion", QuestionSchema);
you can remove the id using filter.
question.upvotes = question.upvotes.filter(upvote => upvote.user.toString() !== req.user.id.toString());
question.save();
add it inside the if condition if this is where you want to remove it.

Usage of mongoose deep-populate unclear

I would like to use the deep-populate plugin for mongoose queries. Most certainly I am to unexperienced but, I don't success to deep-populate something.
Here's my scheme:
var mongoose = require('mongoose');
var MMAnswersSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
item: { type: mongoose.Schema.Types.ObjectId, ref: 'MMItem'},
answer: [
{
skalaAnswer: Number,
freitextAnswer: String,
multipleChoiceAnswer: String,
answered_at: { type: Date, required: true, default: Date.now }
}
],
last_answered: { type: Date, required: true, default: Date.now }
});
MMAnswersSchema.pre('save', function(next) {
this.last_answered = Date.now;
next();
});
mongoose.model('MMAnswer', MMAnswersSchema);
var deepPopulate = require('mongoose-deep-populate')(mongoose);
MMAnswersSchema.plugin(deepPopulate);
Did I put the deepPopulate require stuff at the right place?
I use this route now to get my stuff:
// Alle Antworten des aktuellen Users laden
// Verwendet von der Historie
.get('/mm-answers/:user_id/get-all-answers', function (req, res, next) {
Answer.find({user:req.params.user_id}, function (err, answer) {
if(err){
return next(err);
}
res.json(answer);
})
.deepPopulate('item')
})
I want that it replaces the id with the actual item and the item itself contains a 'ofBox'-field which I also want to be replaced with the actual box document (thats why I use deep-populate).
Using the query above simply doesn't give me any result. I still have the ID in the item field.
If I run the standard .populate('item') command, it replaces the item ID with the item itself but unfortunately not the ofBox ID inside the item. (thats why I need deep-populate).
Can someone help me to figure it out? I guess I made a mistake in importing/ registrating the plugin correctly...-.-
You need to put the deepPopulate call before you execute the query, something like this:
// Alle Antworten des aktuellen Users laden
// Verwendet von der Historie
.get('/mm-answers/:user_id/get-all-answers', function (req, res, next) {
Answer.find({ user: req.params.user_id }).deepPopulate('item').exec(function (err, answer) {
if (err) {
return next(err);
}
res.json(answer);
});
});
In the model you just need to add the fields you wanna populate when you add the plugin:
const mongoose = require('mongoose');
const deepPopulate = require('mongoose-deep-populate')(mongoose);
const MMAnswersSchema = new mongoose.Schema({
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
item: { type: mongoose.Schema.Types.ObjectId, ref: 'MMItem'},
answer: [
{
skalaAnswer: Number,
freitextAnswer: String,
multipleChoiceAnswer: String,
answered_at: { type: Date, required: true, default: Date.now }
}
],
last_answered: { type: Date, required: true, default: Date.now }
});
MMAnswersSchema.pre('save', function(next) {
this.last_answered = Date.now;
next();
});
MMAnswersSchema.plugin(deepPopulate, {
populate: {
user: {
select:'_id name lastName'
},
item: {
select:'_id name'
},
});
const MMAnswers = mongoose.model('answers',MMAnswersSchema);
module.exports = { MMAnswers };
Finally when you need to use the deep population JUST add whatever field you wanna populate
await MMAnswers.findOne({your search}).deepPopulate('user').exec();
or
await MMAnswers.findOne({your search}).deepPopulate('user item').exec();

Categories