I am creating some rest API with ActionHero js and Mongoose.
I put the Mongoose code in an initalizers and everything works.
When I modify some files the project automatically recompiles and it returns the following error: OverwriteModelError:
Cannot overwrite User model once compiled.
How should I edit my code to avoid this error?
'use strict';
var mongoose = require('mongoose');
exports.mongo = function(api, next) {
mongoose.connect(api.config.mongo.host);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log('Connection opened');
});
var Schema = mongoose.Schema,
Types = mongoose.Schema.Types;
var userSchema = mongoose.Schema({
createdAt: { type: Date, default: Date.now(), required: true},
updatedAt: { type: Date, required: false},
email: { type: String, required: true },
name: { type: String, required: true },
surname: { type: String, required: true },
password: { type: String, required: true },
roles: [],
tokens: [{
code: String,
expiryDate: { type: Date, default: Date.now() + 30 }
}]
});
var User = mongoose.model('User', userSchema);
var postSchema = mongoose.Schema({
createdAt: { type: Date, default: Date.now(), required: true},
updatedAt: { type: Date, required: false},
content: { type: String, required: true },
votes: { type: [Types.ObjectId], ref: 'User' } ,
coordinates: { type: [Number], index: { type: '2dsphere' }, required: true },
creator: { type: Schema.Types.ObjectId, ref: 'User', required: true }
});
var Post = mongoose.model('Post', postSchema);
api.mongo = {
mongoose: mongoose,
user: User,
post: Post
};
next();
};
actionhero will reload any initializers if you are in developmentMode. You should wrap your connection steps within the _start() block, rather than have them run in-line each time. This way, actionhero can re-load the file and not re-run your connection steps.
http://actionherojs.com/docs/core/initializers.html
Related
i am trying to have my post's author's name in frontend. so i want to find the post according to it's user Id. but in model schema i used obejct Id of user in post Schema.
Here is my userSchema:
const mongoose = require('mongoose');
// user schema
const userSchema = new mongoose.Schema(
{
email: {
type: String,
trim: true,
required: true,
unique: true,
lowercase: true
},
name: {
type: String,
trim: true,
},
password: {
type: String,
required: true
},
salt: String,
bio: {
type: String,
trim: true
},
role: {
type: String,
default: 'subscriber'
},
resetPasswordToken: String,
resetPasswordExpire: Date,
},
{
timestamps: true
}
);
module.exports = mongoose.model('User', userSchema);
here is my postSchema model:
const mongoose = require("mongoose");
const PostSchema = new mongoose.Schema({
title: {
type: String,
required: true,
},
content: {
type: String,
required: true,
},
comments: [{
text: String,
created: { type: Date, default: Date.now },
postedBy: { type: mongoose.Schema.ObjectId, ref: 'User'}
}],
created: {
type: Date,
default: Date.now
},
creator: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
},
{
timestamps: true,
},
);
const Post = mongoose.model("Post", PostSchema);
module.exports = Post;
and here is my router for post lists by a specific user id:
exports.postByUser=async(req,res)=>{
try
{
const userID=async()=>{
await User.findById({ _id:req.params.id})
.then(posts=>{
res.status(200).json(posts.name)
})
}
await Post.find({creator: req.params.id})
.then(posts=>{
res.status(200).json(posts)
})
}catch(error){
res.status(500).send({error: error.message});
};
}
router.route('/post/mypost/:id').get(requireSignin,postByUser);
my target is to get a post list where every post's creator would have the user name. how can i achieve that in nodejs?
i have solved this way:
exports.postByUser=async(req,res)=>{
try
{
await Post.find({creator: req.params.id})
.populate({path:'creator', select:'name -_id'})
.then(post=>{
res.status(200).json(post)
})
}catch(error){
res.status(500).send({error: error.message});
};
}
and it worked
Im relatively new to MongoDB and Mongoose. Im much used to MySQL so in used to inner joining tables on calls. Ive read a lot that you can link two Mongoose Schemas to achieve the same outcome. How would like like the two schemas together to when I make a call to get a chore by id it'll return the chore and then for the assignedTo & createdBy have the user scheme data for the said userId?
Chore Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ChoreSchema = new Schema({
title: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
time: {
type: Number,
required: true
},
reaccurance: {
type: [{
type: String,
enum: ['Daily', 'Weekly', 'Bi-Weekly', 'Monthly']
}]
},
reward: {
type: Number,
required: true
},
retryDeduction: {
type: Number,
required: false
},
createdDate: {
type: Date,
default: Date.now
},
createdBy: {
type: String,
required: true
},
dueDate: {
type: Date,
required: true
},
status: {
type: [{
type: String,
enum: ['new', 'pending', 'rejected', 'completed', 'pastDue']
}],
default: ['new']
},
retryCount: {
type: Number,
default: 0,
required: false
},
rejectedReason: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
assignedTo: {
type: String,
required: false,
default: ""
}
});
let Chores = module.exports = mongoose.model('Chores', ChoreSchema);
module.exports.get = function (callback, limit) {
Chores.find(callback).limit(limit);
};
User Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
role: {
type: [{
type: String,
enum: ['Adult', 'Child']
}]
},
birthday: {
type: String,
required: false
},
familyId: {
type: String,
required: true
},
balance: {
type: Number,
required: true,
default: 0.00
}
});
let Users = module.exports = mongoose.model('Users', UserSchema);
module.exports.get = function (callback, limit) {
Users.find(callback).limit(limit);
};
Im trying to link ChoreSchema.createdBy & ChoreScheme.assignedTo by UserSchema._id
How I make the call in Node.js:
exports.index = function(req, res) {
Chore.get(function(err, chore) {
if (err)
res.send(err);
res.json({
message: 'Chore List',
data: chore
});
});
};
Mongoose has a more powerful alternative called populate(),
which lets you reference documents in other collections.
https://mongoosejs.com/docs/populate.html
Here is how you can link ChoreSchema.createdBy and ChoreScheme.assignedTo by UserSchema._id
var mongoose = require('mongoose');
const { Schema, Types } = mongoose;
var UserSchema = new Schema({
firstName: { type: String, required: true },
...
})
var ChoreSchema = new Schema({
title: { type: String, required: true },
...
//The ref option is what tells Mongoose which model to use during population
assignedTo: { type: Types.ObjectId, ref: 'Users' },
createdBy: { type: Types.ObjectId, ref: 'Users' },
})
let Chores = mongoose.model('Chores', ChoreSchema);
let Users = mongoose.model('Users', UserSchema);
Then in your express route handler you can populate assignedTo & createdBy like this
router.get('/chores/:id', function (req, res) {
const choreId = req.params.id;
Chores.find({ _id: choreId })
.populate('createdBy') // populate createdBy
.populate('assignedTo') // populate assignedTo
.exec(function (err, chore) {
if(err) {
return res.send(err)
}
res.json({ message: 'Chore List', data: chore });
});
})
I am trying to create a chat with node.js, Express & MongoDB. I have two mongoose models: for chat room and message.
Room model:
const RoomSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Users',
required: true,
},
messages: {
type: [mongoose.Schema.Types.ObjectId],
ref: 'Messages',
required: true,
},
users: {
type: [mongoose.Schema.Types.ObjectId],
ref: 'Users',
required: true,
},
});
const Room = mongoose.model('Rooms', RoomSchema);
Message model:
const MessageSchema = new mongoose.Schema({
text: {
type: String,
required: true,
},
sendBy: {
type: String,
required: true
}
});
const Messages = mongoose.model('Messages', MessageSchema);
and a function for displaying all messages
prepareMessages: function (name, callback) {
rooms.findOne({
name: name,
}).populate('messages')
.exec(function (err, room) {
let result = '';
if (!room) {
console.log("Chat does not exist");
throw err;
}
else {
room.messages.forEach(function (item, i, arr) {
result += '<dt>' + item.sendBy + '</dt>';
result += '<dd>' + item.text + '</dd>';
});
}
callback(result)
});
},
Why do I get
TypeError: Cannot read property 'sendBy' of undefined?
I tried .populate('rooms.messages'), .populate({path: 'rooms.messages', model:'Messages') and another variants, but it still doesn't work. Help me, please!
In the Room Schema, you're defining the messages as an object with type of Array of ObjectId, while it should be an array of elements, each element is of type ObjectId, messages should be an array of ObjectIds, and users as well
const RoomSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Users',
required: true,
},
messages: [{ // note here messages is an array
type: mongoose.Schema.Types.ObjectId,
ref: 'Messages',
required: true,
}],
users: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Users',
required: true,
}],
});
const Room = mongoose.model('Rooms', RoomSchema);
hope it helps
sendBy should be of type ObjectId
const MessageSchema = new mongoose.Schema({
text: {
type: String,
required: true,
},
sendBy: {
type: mongoose.Schema.Types.ObjectId,
required: true
}
});
const Messages = mongoose.model('Messages', MessageSchema);
ref should be in lowercase.
ref: 'Users', should be changed to ref:'users'
Similarly at all other refs
I have this schema for users:
var mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
mongoose.Promise = global.Promise;
var userSchema = new mongoose.Schema ({
username: {type: String, required: true, unique: true},
password: {type: String},
role: {type: String, required: true},
confirmed: {type: Boolean, required: true, default: false},
active: {type: Boolean, required: true, default: true},
name: String,
created: {type: Date, default: Date.now},
admin: {type: Boolean, default: false, required: true}
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);
And another schema for companies, where clients refer to an array of users:
var mongoose = require("mongoose");
mongoose.Promise = global.Promise;
var companySchema = new mongoose.Schema ({
name: {type: String, required: true, unique: true},
created: {type: Date, default: Date.now},
active: {type: Boolean, required: true, default: true},
staff: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}],
clients: [{
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}]
});
module.exports = mongoose.model("Company", companySchema);
I have the below code in my route, but the user information is not being populated into the company object, what am I doing wrong?
// EDIT route
router.get("/:company_id/edit", middleware.checkCompanyOwnership, function(req, res) {
Company.findOne({_id: req.params.company_id}).populate({path: 'clients'}).exec(function(err, company) {
if (err || !company) {
console.log(err);
req.flash("error", err.message);
res.redirect("/");
} else {
console.log("Request to edit company.");
//console.log(company);
res.render("company/edit", {title: "Edit Company", company: company});
}
});
});
This is what I am getting if I console log company:
{ _id: 5a070874b4292914444b6e06,
name: 'ABC',
__v: 1,
clients:
[ { username: 'abcdefg#gmail.com',
_id: 5a070206616810129b5c876a } ],
staff: [],
active: true,
created: 2017-11-11T14:25:56.359Z }
Thanks for your help.
Your company schema should look like this
var companySchema = new mongoose.Schema ({
...
staff: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
clients: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }]
});
See the docs http://mongoosejs.com/docs/populate.html
I'm completely new to the NoSQL world and it's been difficult to wrap my mind around it. This week I was learning MongoDB (Mongoose) with Node.js and here is my current schema:
var eventDataSchema = new Schema({
_id : Number,
notes : {type: String, required: true},
start_date : {type: Date, required: true},
end_date : {type: Date, required: true},
}, {
id : false,
collection : 'event-data'
});
eventDataSchema.plugin(AutoIncrement);
var EventData = mongoose.model('EventData', eventDataSchema);
Now that this is working, I would like to add a user and password and have access to have personal access to EventData.
Also... later if I want to send a JSON of only the eventData, but not the user to my javascript, how would I do that?
The way I am currently sending my eventData to my js in this format:
router.get('/data', function(req, res){
EventData.find({}, function(err, data){
if (err) {
console.error('Error occured');
}
res.send(data);
});
});
Thanks again
As i can understand you want to add events key in your schema. Then your schema will be like that:
var userSchema = new Schema({
user: { type: String, required: true, trim: true },
password: { type: String, required: true, trim: true },
events: [{
notes: { type: String,required: true, trim: true },
start_date: { type: Date,required: true },
end_date: { type: Date,required: true }
}]
}
userSchema.plugin(AutoIncrement);
var userSchema = mongoose.model('userSchema', userSchema);
});
If the above code is not working then you can create two schema,one for user and other for eventData, and can populate your eventData in userSchema.
so your code will be like that:
userSchema.js:
var userSchema = new Schema({
user: { type: String, required: true, trim: true },
password: { type: String, required: true, trim: true },
events: {type: mongoose.Schema.Types.ObjectId, ref: 'EventData' }
userSchema.plugin(AutoIncrement);
module.exports = mongoose.model('userSchema', userSchema);
});
And your eventDataSchema will be:
eventSchema.js:
var eventDataSchema = new Schema({
notes: { type: 'string',required: true, trim: true },
start_date: { type: Date,required: true },
end_date: { type: Date,required: true }
}
eventDataSchema.plugin(AutoIncrement);
module.exports = mongoose.model('EventData', eventDataSchema);
});
and then you can get the result like that:
index.js:
var eventSchema = require('./eventSchema');
var userSchema = require('./userSchema');
var populate = [{
path: 'events',
model: 'EventData',
select: '_id notes start_dat end_date'
}];
var find = function (query) {
return userSchema.find(query).populate(populate).exec();
}
console.log(find());
Result:
{
_id:cfgvhbjnkmkdcfxghgjklxnmbxhdhjxjhjhgx,
user: John Doe,
password: 123,
events: [ { _id: 1gfye56785g3ycgevhxeftx568765egcd,
notes: Event A,
start_date: 1/1/01,
end_date: 1/1/01
} ]
}