Turn String into Mongoose Model - javascript

I'm learning how to make Mongoose models in Express right now and was wondering if there is a way to convert a string into a matching model.
For instance, if I have a Mongoose model called "User" and a variable like const name = "User", is there a way to convert the string "User" into a User model? Specifically, is there a way to make the following code work?
const name = 'User';
name.findByIdAndUpdate()

Suppose this was the model:
const schema = new mongoose.Schema({ name: 'string' });
const User = mongoose.model('User', schema);
const name = 'User';
Now use the model to construct a document:
const user = new User({ name });
user.save(function (err) {
if (err) return handleError(err);
// saved!
});
or
User.create({ name }, function (err, user) {
if (err) return handleError(err);
// saved!
});
or
const user = await User.create({ name });
Now you can use:
User.findByIdAndUpdate(user.id, { ... }, { ... });
Reference: https://mongoosejs.com/docs/models.html.

Related

Reference another Schema in Mongoose

so I have to Schemas. PostSchema and UserSchema
const mongoose = require("mongoose")
const PostSchema = new mongoose.Schema({
content: {
type: String,
required: true,
},
likes: {
type: Number,
required: true
},
rescreams: {
type: Number,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model("Post", PostSchema)
UserSchema:
const bcrypt = require("bcrypt");
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
userName: { type: String, unique: true },
email: { type: String, unique: true },
password: String,
});
// Password hash middleware.
UserSchema.pre("save", function save(next) {
const user = this;
if (!user.isModified("password")) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
});
// Helper method for validating user's password.
UserSchema.methods.comparePassword = function comparePassword(
candidatePassword,
cb
) {
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
cb(err, isMatch);
});
};
module.exports = mongoose.model("User", UserSchema);
My question is: I'm trying to reference the User Object ID in the Post Schema. As you can see, I've done that with type: mongoose.Schema.Types.ObjectID. And I've seen this multiple times. But in my database, the User never shows up in the Document. What do I need to do?
Cheers
There is a difference between referencing a document and embedding a document.
If you want to store a document inside a document you should embed it, thus read operations will be faster because you won't need to perform JOIN operations.
Whereas referencing means storing an ID of an entity that you are referencing, when you need to access the document you are referencing, you need to fetch it from the collection by the ID you have stored. It is slower than embedding, but it gives you higher consistency and data integrity because the data is stored once at the collection and not duplicated at every object. And MongoDB does not support foreign keys so you should be careful with referencing.
So when you are storing the document using ref, you need to put an ObjectID as a user and then fetch the document you need to add populate call. e.g.
PostShema.findOne({ _id: SomeId }).populate('user');
try to save in a variable:
const UserId = UserSchema.Schema.Types.ObjectId;
for more information:
https://mongoosejs.com/docs/api/schema.html#schema_Schema.Types

how to fix mongoose array in node

i'm trying to push objects into my mongodb db.
I'm able to view said data when pushed in my console.log. but they arent pushed into the db at all.
Below is my app.js code..
const userSchema = new mongoose.Schema({
email : String,
password: String,
selectedPet : [String]
});
userSchema.plugin(passportLocalMongoose);
const User = new mongoose.model("User", userSchema);
app.post("/prototype",(req, res) =>{
var animalSelected = [];
animalSelected.push = req.body.selectedPet;
console.log(req.user.id, animalSelected);
User.findById(req.user.id, function(err, foundUser){
if (err){
console.log(err);
} else {
if (foundUser){
foundUser.selectedPet = animalSelected;
foundUser.save(function(){
res.redirect("/proto")
});
}
}
});
});

why mongoose won't create an ObjectID

I have a JSON web token that once it's verified gives me a string that is the object id value of a user I want to find but it seems that every time I try to query with it being parsed into a mongoose object ID it never find my user, am I parsing it right ? I always get a 401 invalid token paylaod
logRoute.get('/user', (req, res) => {
let token = req.body;
User.findOne({_id: mongoose.Types.ObjectId(jwt.verify(token.token, 'secretkey').subject)}, (error, user) => {
if (error) {
console.log(error)
} else {
if (!user) {
res.status(401).send('invalid token payload')
} else {
let userData = {firstname: user.firstname, lastname: user.lastname, type: user.type}
res.status(200).send(userData)
}
}
})
})
my user data
{
"_id": {
"$oid": "5efc7d60ba7a8d3db08ca767"
},
"type": "teacher",
"firstname": "arandomfirstname",
"lastname": "arandomlastname",
"login": "random1",
"pwd": "arandompassword"
}
and
console.log(jwt.verify(req.body.token, 'P3GPROJECT'))
return me
{ subject: '5efc7d60ba7a8d3db08ca767', iat: 1593690718 }
EDIT:
User model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
_id: String,
pwd: String,
lastname: String,
firstname: String,
type: String
});
module.exports = mongoose.model('user', userSchema, 'user');
You've to remove _id: String from model schema, since You've ObjectId as a value (not a string) and it makes mongoose to convert Your input to string, instead of ObjectId.
so:
const userSchema = new Schema({
_id: String,
pwd: String,
lastname: String,
firstname: String,
type: String
});
becomes:
const userSchema = new Schema({
pwd: String,
lastname: String,
firstname: String,
type: String
});
or You can keep it as string but have to define the logic of generation of proper _id:
const uuid = require('short-uuid');
const userSchema = new Schema({
_id: {
type: Schema.Types.String,
default: uuid.generate(), // this will generate unique string
},
pwd: String,
lastname: String,
firstname: String,
type: String
});
P.S. Keep in mind if You want to use _id: String, You've to remove old documents or convert them manually to be {_id: "id here"} instead of {_id: ObjectId("id here")}.
Bonus:
Also I recommend You to create middlewares and separate token handling, from user authorization check.
It will allow You to not repeat access token checking in every request and will help You to understand in which step You're doing it wrong.
And then to do what You want.
jwt.verify throws error if it's invalid, that's why I put try catch arount.
I'm extracting subject as userId and if it does not exist it also means that token invalid, otherwise I pass handling to next handler in routing.
authorizeUser gets req.accessToken.userId from previous middleware and tries to check if user exists. If yes - so it stores complete user object in req.user, otherwise will end with 401 also.
and at last route handling goes last step which does logic or it can be empty as res.status(200).send(req.user)
const checkAccessToken = (req, res, next) => {
try {
const {subject: userId} = jwt.verify(req.body.token, 'secretkey');
if (!userId) throw new Error('Token data does not contain user id');
req.accessToken = {userId};
next();
}
catch (error) {
console.error(error);
res.status(401).send({message: 'Invalid access token'});
}
};
const authorizeUser = async (req, res, next) => {
try {
const user =
await User.findById(req.accessToken.userId)
.select('_id firstname lastname type')
.lean();
if (!user) {
return res.status(401).send({message: 'Unauthorized'});
}
req.user = user;
req.user.id = req.accessToken.userId;
next();
}
catch (error) {
console.error(error);
res.status(500).end();
}
};
logRoute.get(
'/user',
checkAccessToken, // checking token and putting user id to `req.user.id`
authorizeUser, // checking if user exists in database and putting it as `req.user` object
async (req, res) => { // handling some logic or simply returning `req.user` object
// some extra logic here...
res.status(200).send(req.user);
}
);

Mongoose findOne() callback returning null

I'm trying to find a user in my node app with mongoose by using
var User = require('../app/models/user');
function mongoTest() {
var publicAddress = "0x8a6be8979340faa30020b0c1f617d8fd4309679f";
User.findOne({"publicAddress": publicAddress}, (err, user) => {
if (err) {
res.status(500).send(err)
} else {
console.log(user);
}
});
}
and err and user always return null. From other questions here (this and this), this usually seems to be related to mongoose pluralising collections. However, I don't think that's my issue because my users.js has
module.exports = mongoose.model('User', userSchema);
// Have also tried module.exports = mongoose.model('User', userSchema, 'User');
For completeness, users.js is
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// Define the schema for our user model
var userSchema = mongoose.Schema({
local: {
username: String,
password: String,
pictureCaption: String,
publicAddress: String,
contractAddress: String
}
});
Finally, I'm sure that public address exists because I can see it in the mongoDB with Robo 3T.
In your userSchema the publicAddress is part of local object.
var userSchema = mongoose.Schema({
local: {
username: String,
password: String,
pictureCaption: String,
publicAddress: String,
contractAddress: String
}
});
You are trying to find an object with publicAddress but it's actually inside the local object. So you should edit the query as follows to get the result.
User.findOne({"local.publicAddress": publicAddress}, (err, user) => {
if (err) {
res.status(500).send(err)
} else {
console.log(user);
}
});

Mongoose save doesn't work "id is not defined"

It's my first time using Mongoose and the save function is not working for me...
On user model file:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var User = mongoose.model('User', {
name: Schema.Types.Mixed,
gender: String,
email: String
});
module.exports = User;
On my user controller file:
// Create a user
router.post('/', function(req, res) {
var user = new User(req.body);
user._id = mongoose.Types.ObjectId();
user.save(function(err) {
if (err) {
return res.status(500).json({
error: "Error creating user: " + err
});
}
return res.status(200).end();
});
});
I tried everything but I can't save the user object to the database: "id is not defined"
On the db the _id is a ObjectId.
Thanks.
mongoose.model receives collection name and a Schema as arguments, not an regular object.
So you should use the following code instead:
var schema = new mongoose.Schema({
name: Schema.Types.Mixed,
gender: String,
email: String
});
var User = mongoose.model('User', schema);
maybe we can change the code structure && remove "user._id", test please this code :
*model file:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: Schema.Types.Mixed,
gender: String,
email: String
});
module.exports = mongoose.model('User', UserSchema);
*controller file:
// Create a user
router.post('/', function(req, res) {
var user = new User(req.body);
user.save(function(err) {
if (err) {
return res.status(500).json({
error: "Error creating user: " + err
});
}
return res.status(200).end();
});
});

Categories