mongoose add array to subdocuments - javascript

I have a signup shema:
const mongoose = require("mongoose");
const signupSchema = mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
cargoId: { type: mongoose.Schema.Types.ObjectId, ref: "Cargo", required: true },
truckIds: [{
truckId: {type: mongoose.Schema.Types.ObjectId, ref: "Truck", required: true }
}],
approved: { type: Boolean ,required: true },
finished: { type: Boolean ,required: true }
});
module.exports = mongoose.model("Signup", signupSchema);
and controller:
exports.createSignup = (req, res, next) => {
console.log(req.body.truckIds);
const signup = new Signup({
userId: req.userData.userId,
cargoId: req.body.cargoId,
truckIds: req.body.truckIds,
approved: req.body.approved,
finished: req.body.finished,
cmrCreated: false
});
signup.save()
.then(result => {
res.status(201).json({
message: "Signup created!",
result: result
});
})
.catch(err => {
res.status(500).json({
message: "DB error!"
});
});
}
I want to insert data to collection to have something like this:
{
"_id" : ObjectId("616d536c8e61e369ca82f2e4"),
"userId" : ObjectId("60868c31caafe530e7e2d04a"),
"cargoId" : ObjectId("614da0b0812a2f6169163d37"),
"truckIds" : [id1,id2.....],
"approved" : false,
"finished" : false,
"__v" : 0
}
I don't know how to insert subdocuments(truckIds) into a collection. Thank you in advance.

Related

postman returning null with 200 status code

getting null value as response with 200 status code. i want to see the profile details as response but instead of that showing null value with no error status code in my postman i dont find any error on my code. why it shows like this ? i want to see profile details as response after sending
Router.post
router.post(
'/',
[
auth,
[
check('status', 'Status is required').not().isEmpty(),
check('skills', 'Skills cannot be empty').not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubusername,
skills,
youtube,
twitter,
instagram,
linkedin,
} = req.body;
const profileFields = {};
profileFields.user = req.user.id;
if (company) profileFields.company = company;
if (website) profileFields.website = website;
if (location) profileFields.location = location;
if (bio) profileFields.bio = bio;
if (status) profileFields.status = status;
if (githubusername) profileFields.githubusername = githubusername;
if (skills) {
profileFields.skills = skills.split(',').map(skill => skill.trim());
}
// creating object for socila links
profileFields.social = {};
if (youtube) profileFields.social.youtube = youtube;
if (twitter) profileFields.social.twitter = twitter;
if (instagram) profileFields.social.instagram = instagram;
if (linkedin) profileFields.social.linkedin = linkedin;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile)
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
// create
profile = new Profile(profileFields);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err);
res.status(500).send('server error');
}
}
);
here is profile schema looks like
const ProfileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
status: {
type: String,
required: true,
},
location: {
type: String,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile',ProfileSchema)
your code logic has problem.
let profile = await Profile.findOne({ user: req.user.id }); if (profile) //update profile = await Profile.findOneAndUpdate( { user: req.user.id }, { $set: profileFields }, { new: true } ); return res.json(profile);
here, if you can't find the record in database, you still return and there is no value so that you got null response. i suggest you remoe the return res.json(profile); into if statement
Back to the basics, the if statement.
if (profile){
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
}
You need to use brackets {}.
In your code, return res.json(profile); gets fired no matter if the response is null or not
the problem is with your syntax you need to add curly braces
if (profile){
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)};

findByIdAndUpdate pull from array objects equal to a specific value

I want to remove one or more objects of type tweet from the timeline list within the user model. The tweet objects that I want to remove are those whose author id matches a specific id user._id.
I have tried this:
router.get("/follow/:userId", isLoggedIn, catchAsync(async (req, res) => {
try {
const currentUser = await User.findById(req.user._id).populate("timeline")
const user = await User.findById(req.params.userId).populate("followers tweets")
for (let tweet of currentUser.timeline) {
if (tweet.author._id.equals(user._id)) {
currentUser.timeline.pull(tweet._id)
}
}
req.flash("error", `Unfollowed to ${user.username}`)
user.save();
currentUser.save()
res.redirect(`/${user._id}`)
} catch (err) {
req.flash("error", err.message);
res.redirect("back")
}
}));
and this:
await User.findbyIdAndUpdate(currentuser._id, { $pull: { timeline: { author : user._id } } }
but none of them are working.
My user model:
const userSchema = new Schema({
name: {
type: String,
required: true
},
biography: { type: String, maxlength: 160 },
location: {type: String, maxlength: 30 },
email: {
type: String,
unique: true,
required: true
},
image: {
url: String,
filename: String,
},
followers: [{ type: Schema.Types.ObjectId, ref: "User" }],
following: [{ type: Schema.Types.ObjectId, ref: "User" }],
tweets: [{ type: Schema.Types.ObjectId, ref: "Tweet"}],
timeline: [{ type: Schema.Types.ObjectId, ref: "Tweet"}]
});
My tweet model :
const tweetSchema = new Schema({
images: [{
url: String,
filename : String
}],
text: { type: String, maxlength: 260},
date: { type: Date, default: Date.now },
author: { type: Schema.Types.ObjectId, ref: "User" },
parent: { type: Schema.Types.ObjectId, ref: "Tweet", default:null },
replies: [{ type: Schema.Types.ObjectId, ref: "Tweet" }],
likes: [{ type: Schema.Types.ObjectId, ref: "User" }],
retweets: [{ type: Schema.Types.ObjectId, ref: "Tweet" }],
retweetStatus: {type: Schema.Types.ObjectId, ref: "Tweet", default: null}
});
If your collection looks like this:
[
{
"_id" : ObjectId("60254276259a60228cbe5707"),
"name" : "Mary",
"timeline" : [
ObjectId("60254276259a60228cbe5703"),
ObjectId("60254276259a60228cbe5704"),
ObjectId("60254276259a60228cbe5705")
]
},
{
"_id" : ObjectId("60254276259a60228cbe5706"),
"name" : "Dheemanth",
"timeline" : [
ObjectId("60254276259a60228cbe5700"),
ObjectId("60254276259a60228cbe5701"),
ObjectId("60254276259a60228cbe5702")
]
}
]
then the solution is:
usersSchema.updateOne(
{
"_id": ObjectId("60254276259a60228cbe5706"),
"timeline": ObjectId("60254276259a60228cbe5700"),
},
{
$pull: {
"timeline": ObjectId("60254276259a60228cbe5700")
}
}
)
.then()
.catch()
// or
usersSchema.findOneAndUpdate(
{
"_id": ObjectId("60254276259a60228cbe5706"),
"timeline": ObjectId("60254276259a60228cbe5700"),
},
{
$pull: {
"timeline": ObjectId("60254276259a60228cbe5700")
}
},
{
new: true
}
)
.then()
.catch()
I finally found the issue! The problem I was having is that I was trying to remove items from a list of objects while looping through that list. The solution is easy: you can just create an auxiliar empty array and push the items that you want to remove, then loop through that auxiliar array and pull the items from the original array.
In my case, I've already had an array with the tweets that I wanted to remove, user.tweets. The solution is:
router.get("/follow/:userId", isLoggedIn, catchAsync(async (req, res) => {
try {
const currentUser = await User.findById(req.user._id).populate("timeline")
const user = await User.findById(req.params.userId).populate("followers tweets")
for (let tweet of user.tweets) {
currentUser.timeline.pull(tweet._id)
}
req.flash("error", `Unfollowed to ${user.username}`)
user.save();
currentUser.save()
res.redirect(`/${user._id}`)
} catch (err) {
req.flash("error", err.message);
res.redirect("back")
}
}));

Try to populate in mongoose and it doesn't work (nodejs)

i Make mini cart with Product and user Auth, Evereting work perfect but whan i try to make a route that pickup all the product from the user and view them in specific page and it not work for me.
it returns the user but not the product.
UserSchema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
product: {
type: [mongoose.Schema.Types.ObjectId],
ref: "product"
},
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
address: {
type: String,
required: true
},
password: {
type: String,
required: true
},
data: {
type: Date,
default: Date.now
}
});
module.exports = User = mongoose.model("user", UserSchema);
ProductScheama
const mongoose=require('mongoose');
const ProductSchema = new mongoose.Schema({
name:{
type:String,
required:true,
unique:true
},
description:{
type:String,
},
price:{
type:Number,
required:true
},
quantity:{
type:Number,
required:true
},
data:{
type:Date,
default:Date.now
}
})
module.exports=Product=mongoose.model('product',ProductSchema)
I am trying to create a function that gives me the name, price and description of the product and it fails.
my router:
router.get("/products/:id", auth, async (req, res) => {
try {
let pro = await User.find({ product: req.params.id }).populate("product", [
"name",
"price",
"description"
]);
if (!pro) {
return res.json({ msg: "This user not have products to show" });
}
res.json(pro);
} catch (err) {
console.error(err.message);
res.status(500).send("Server errors");
}
});
result from Postman:
[
{
"product": [],
"_id": "5d5bfb96963ca600ec412bca",
"name": "Anonny Annon",
"email": "Annony#gmail.com",
"address": "Israel",
"password": "$2a$10$gESTIaBVifzhRDR2zOKsw.Q79gCT07IK2VnDoyT2oU5htqfBuAj8W",
"data": "2019-08-20T13:54:30.267Z",
"__v": 0
}
]
I think product should be defined this way :
product: [{
type: mongoose.Schema.Types.ObjectId,
ref: "product"
}]
instead of type: [mongoose.Schema.Types.ObjectId]
Solution found here

How can I limit the returned items from a Mongoose array populate?

I have a model that we use for a conversational chat, that uses nested arrays. Each time a user sends a message, it gets pushed into the messages array. This is my model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ConversationSchema = new Schema({
sender: {
type: Schema.Types.ObjectId,
ref: 'User'
},
messages: [
{
message: String,
meta: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
delivered: Boolean,
read: Boolean
}
]
}
],
is_group_message: { type: Boolean, default: false },
participants: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
delivered: Boolean,
read: Boolean,
last_seen: Date
}
]
}, { timestamps: true });
module.exports = mongoose.model('Conversation', ConversationSchema);
I'm trying to find all conversations, that a user is a part of, but I'm unable to return only the most recent chat message, and it seems to ignore the options. Is this a model or populate issue on my end?
Conversation.find({ 'participants.user': { $all: [req.user._id] } })
.sort('-createdAt')
.populate({
path: 'sender',
select: '-_id -password -email -lastLogin -createdAt -updatedAt -__v',
})
.populate({
path: 'messages.meta.user',
select: 'username avatar',
options: {
limit: 1
}
})
.populate({
path: 'participants',
path: 'participants.user',
select: 'username avatar'
})
.then(conversation => {
if (!conversation) {
errors.noconversation = 'No conversation could be found';
return res.status(404).json(errors);
}
res.json(conversation)
})
.catch(err => res.status(404).json({ conversation: 'There are no conversations or an error occurred' }));

Can't POST to nested array with express js

It's my first post here so please let me know if there's anything incomplete about my question, or if there's anything else that is missing :)
I'm trying to make a POST request to an array in my data structure called features:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CategorySchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
categoryname: {
type: String,
required: true
},
items: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
itemname: {
type: String,
required: true
},
features: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
firstfeature: {
type: String
},
date: {
type: Date,
default: Date.now
}
},
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
secondfeature: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
}
],
date: {
type: Date,
default: Date.now
}
});
module.exports = Category = mongoose.model('category', CategorySchema);
I don't have any issues with posting to the items array with the following code:
router.post(
'/item/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateItemInput(req.body);
// Check Validation
if (!isValid) {
// if any errors, send 400 with erros object
return res.status(400).json(errors);
}
Category.findById(req.params.id)
.then(category => {
const newItem = {
itemname: req.body.itemname,
user: req.user.id
};
// Add to item array
category.items.unshift(newItem);
// Save
category.save().then(category => res.json(category));
})
.catch(err =>
res.status(404).json({ categorynotfound: 'No category found' })
);
}
);
But I can't figure out what I need to change here in order to add data to the features array:
router.post(
'/feature/:id/:item_id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Category.findById(req.params.id)
.then(category => {
const newFeature = {
firstfeature: req.body.firstfeature,
secondfeature: req.body.secondfeature,
user: req.user.id
};
// Add to item array
category.items.features.unshift(newFeature);
// Save
category.save().then(category => res.json(category));
})
.catch(err => res.status(404).json({ itemnotfound: 'Item not found'
}));
}
);
Issue solved with the following data structure:
features: [
{
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
price: {
type: String
},
size: {
type: String
},
date: {
type: Date,
default: Date.now
}
}
]
And then simply make a post request for one feature at a time.

Categories

Resources