I found this on the documentation for mongoose:
Subdocuments have save and validate middleware just like top-level
documents. Calling save() on the parent document triggers the save()
middleware for all its subdocuments, and the same for validate()
middleware.
But that hasn't been working for me. when I call save on my parent, the subdocument doesn't get created in its own collection. Here's my code:
Cart Model
const mongoose = require("mongoose");
const cartSchema = new mongoose.Schema({
numOfSessions: {
type: Number,
required: true
},
status:{
type: String,
enum: ["completed", "active", "deleted"],
required: true
}
}, { timestamps: true, versionKey: false });
const Cart = mongoose.model('shoppingCart', cartSchema);
module.exports = Cart;
User Model
const mongoose = require("mongoose");
const Cart = require("./xxxx").schema
const Schema = mongoose.Schema;
const userSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
password: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true
},
shoppingCarts: [ Cart ]
}, { timestamps: true, versionKey: false });
const User = mongoose.model('user', userSchema);
module.exports = User;
Server Side
const new_user = new User({
firstName: req.body.firstname,
lastName: req.body.lastname,
username: req.body.username,
phoneNum: req.body.phone,
userType: req.body.userType,
email: req.body.email,
password: hashedPassword
});
new_user.shoppingCarts.push(new_cart);
console.log('pushed')
new_cart.save(); //If i take out this line, this subdocument doesn't get saved
new_user.save()
.then((result) => {
console.log(result);
});
To save the subdocument, I'm having to call save on it them well. Is this how it's supposed to be? Thx :D
Related
I'm trying to find out the way to remove nested object in one collection once the document from another collection is expired
LocationsSchema.js
const mongoose = require('mongoose');
const locationsSchema = mongoose.Schema({
name: {
type: String,
required: [true, 'Please add a location name (string)']
},
confirmedBookings: [
{
startDate: {
type: Number
},
finishDate: {
type: Number
}
}]
}, {
timestamps: true
})
module.exports = mongoose.model('Locations', locationsSchema)
BookingsSchema.js
const mongoose = require('mongoose');
const Location = require('./locationModel');
const bookingSchema = mongoose.Schema({
startDate: {
type: Number,
required: [true, 'Please add a valid Date']
},
finishDate: {
type: Number,
> timestamp
required: [true, 'Please add a valid Date'],
index: true
},
location: {
type: mongoose.Schema.Types.ObjectId,
ref: Location
}
}, {
timestamps: true
})
bookingSchema.index({finishDate: 1}, {expireAfterSeconds: 0})
module.exports = mongoose.model('Booking', bookingSchema)
This is how I delete the object manually in
BookingsController.js
const deleteBookings = asyncHandler(async (req, res) => {
const booking = await Booking.findById(req.params.id);
if (!booking) {
res.status(400);
throw new Error('Booking not found');
}
await Location.findOneAndUpdate({_id: booking.location},
{$pull: {'confirmedBookings': {_id: req.params.id}}});
await booking.remove();
res.status(200).json({id: req.params.id});
})
But I also want to be able to delete the objects ones theirs finishDate are before the present time.
I tried to create an TTL index for that but it seems it doesn't work in the way I did it
Im having issues populating my mongoDB collection with another collection based off the _id. It Keeps returning an empty object with no errors or anything?
Property Schema
const PropertySchema = new Schema({
landlord: {
type: Schema.Types.ObjectId,
ref: "Landlord",
required: true,
},
...
});
Landlord Schema
import { Schema as _Schema, model } from "mongoose";
const Schema = _Schema;
const LandlordSchema = new Schema({
fname: {
type: String,
required: true,
},
lname: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
email: {
type: String,
required: true,
},
company: {
type: String,
},
});
const Landlord = (module.exports = model("Landlord", LandlordSchema));
export function get(callback, limit) {
Landlord.find(callback).limit(limit);
}
Property Controller
exports.readProperty = async (req, res) => {
await Property.find({ _id: req.params.propertyId })
.populate({
path: "Landlord",
select: "fname lname email phone company",
model: "Landlord",
strictPopulate: false,
})
.then(function (err, property) {
if (err) return res.send(err);
res.json(property);
});
};
mongodb Property Collection
Mongodb Landlord Collection
When running the get call from postman it returns:
I fixed this issue by selecting the field: landlord not Landlord
I have a project with the following document flow.
Users -> Accounts -> Projects
Users
Users have specific roles
Accounts
CRUD conditioned by User role
Specific users will have access to individual accounts. I was thinking to add an array userGroup with user id's?
Projects
Nested under Accounts related to a single accountToken ID
CRUD conditioned by User role
Specific users will have access to individual projects.
Here are example Schema models simplified for demo purposes.
UserSchema.js:
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please add an email'],
unique: true,
},
role: {
type: String,
enum: ['admin', 'user'],
default: 'user'
}
});
module.exports = mongoose.model('User', UserSchema);
AccountSchema.js:
const AccountSchema = new mongoose.Schema({
accountName: {
type: String,
},
accountToken: {
type: String
}
});
module.exports = mongoose.model('Account', AccountSchema);
ProjectSchema.js:
const ProjectSchema = new mongoose.Schema({
projectName: {
type: String,
},
projectType: String,
projectToken: String
})
module.exports = mongoose.model('Project', ProjectSchema);
I am stuck on the best way to setup nested or sub-document Schema Relations and the best way to relate the data between each other. Any guidance and suggestions would be a huge help! Thanks!!!
Try this;
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, 'Please add an email'],
unique: true,
},
role: {
type: String,
enum: ['admin', 'user'],
default: 'user'
}
});
module.exports = mongoose.model('User', UserSchema);
const AccountSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
accountName: {
type: String,
},
accountToken: {
type: String
}
});
module.exports = mongoose.model('Account', AccountSchema);
const ProjectSchema = new mongoose.Schema({
accountTokenId:{
type: String
},
projectName: {
type: String,
},
projectType: String,
projectToken: String
})
module.exports = mongoose.model('Project', ProjectSchema);
I want to populate a query with mongoose, using the "populate" method. I'm using the most recent/stable version of mongoose. The relevant parts of my schema are defined as shown below. The problem is that when I try to populate const sessions = await Session.find().populate({ path: "coach", select: "name email" }), I always get "coach": null.
I expected it to simply return the sessions that match my query together with the coach (user) object. What am I doing wrong here?
UserSchema
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, "email is required"],
unique: [true, "email must be unique"],
match: [/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/, "Invalid email"]
},
name: {
type: String,
required: [true, "name is required"]
},
(....)
});
export const User = mongoose.model('User', UserSchema);
SessionSchema
const mongoose = require('mongoose');
const SessionSchema = new mongoose.Schema({
coach: { type: mongoose.Schema.ObjectId, ref: 'User', required: true },
location: {
street: { type: String }
},
(......)
});
export const Session = mongoose.model('Session', SessionSchema);
I think the coach type should be the following (Schema.Types seems to be missing):
coach: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
I've found it. Sorry, guys. The code is ok. The problem was that I was seeding my DB with entries that had a "id" property, not a "_id" property. So, the "id" was not getting saved properly and thus the response was actually null.
I want the post's creator to be a user Schema. So i have 2 Schema
post.js
const mongoose=require('mongoose');
mongoose.Promise = global.Promise;
const Schema= mongoose.Schema;
const postSchema= new Schema({
body:{ type: String, required:true, validate:bodyValidators},
createdBy: { type: Schema.Types.ObjectId,ref:'User'}, // this one
to: {type:String, default:null },
createdAt: { type:Date, default:Date.now()},
likes: { type:Number,default:0},
likedBy: { type:Array},
dislikes: { type:Number, default:0},
dislikedBy: { type:Array},
comments: [
{
comment: { type: String, validate: commentValidators},
commentator: { type: String}
}
]
});
module.exports = mongoose.model('Post',postSchema);
user.js
const mongoose=require('mongoose');
mongoose.Promise = global.Promise;
const Schema= mongoose.Schema;
const userSchema=new Schema({
email: { type: String, required: true, unique: true, lowercase: true, validate: emailValidators},
username: { type: String, required: true, unique: true, lowercase: true, validate: usernameValidators},
password: { type: String, required: true,validate: passwordValidators},
bio: { type:String,default:null},
location: {type:String, default:null},
gender: {type:String,default:null},
birthday: { type:Date,default:null},
img: { type:String, default:'Bloggy/uploads/profile/avatar.jpeg'}
});
module.exports = mongoose.model('User',userSchema);
When a user creates a new post, I save his _id into a new post object
const post= new Post({
body: req.body.body,
createdBy:user._id,
createdAt:Date.now()
});
And when i want to recover all posts with their assigned author
router.get('/allPosts',(req,res)=>{
Post.find().populate('createdBy').exec((err,posts)=>{
if(err){
res.json({success:false,message:err});
}
else{
if (!posts) {
res.json({success:false,message:"No posts found"});
}
else{
res.json({success:true,posts:posts});
}
}
}).sort({'_id':-1}); // the latest comes first
});
It doesn't work though i've followed the documentation. The error i get is TypeError: Post.find(...).populate(...).exec(...).sort is not a function
What am I doing wrong ? Am I missing something ? Maybe the fact that both models are not in the same file ?
Remove execPopulate() it might work. It worked for me.
.exec() returns a Promise and has no method called .sort().
.sort() goes before .exec() as in Post.find(...).populate(...).sort(...).exec(...)
Look at 3rd example in the documentation.