why save function works with (user) even though user does not have this function
and when I print user it doesn't have any save function
I did not use findByIdAndUpdate because I wanna use pre before save or update user
I searched on google but didn't find a solution
index.js
const User = require('../models/user')
user = await User.findById(req.params.id)
user['password']='xxxxx'
await user.save()
User File
const mongoose = require('mongoose')
const validator = require('validator')
const bcrypt=require('bcryptjs')
const userSchema=mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail(value)) {
throw new Error('Email is invalid')
}
}
},
password: {
type: String,
required: true,
minlength: 7,
trim: true,
validate(value) {
if (value.toLowerCase().includes('password')) {
throw new Error('Password cannot contain "password"')
}
}
},
age: {
type: Number,
default: 0,
validate(value) {
if (value < 0) {
throw new Error('Age must be a postive number')
}
}
}
})
userSchema.pre('save', async function (next) {
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next()
})
const User = mongoose.model('User',userSchema )
module.exports = User
console.log(user) output
{
age: 20,
_id: 5f738c48bbf1cc3b2647a35b,
name: 'momo',
email: 'momomo#gmail.com',
password: 'sj,sksaklas,ans',
__v: 0
}
console.log(user['save']) output
[Function (anonymous)]
The User value is returned by the function call mongoose.model('User',userSchema )
The save() function is defined here: https://github.com/Automattic/mongoose/blob/master/lib/model.js#L424-L505
When you pass an object to console.log it typically displays only the objects own properties, not inherited ones. i.e. save is not displayed when logging a mongoose model for the same reason that console.log doesnn't display match, indexOf, ltrim, replace, etc. when logging a string.
If you really want to see the inherited properties, this might be a starting point for you:
How to console.log all inherited properties?
Related
connection api
import mongoose from "mongoose";
const MONGODB_URL = NEXT_MONGO_URL
if (!MONGODB_URL) {
throw new Error(error);
}
let cached = global.mongoose;
if (!cached) {
cached = global.mongoose = {
conn: null,
promise: null,
};
}
async function dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
};
cached.promise = mongoose.connect(MONGODB_URL, opts).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
user api
__________________________________________________________________________
var mongoose = require("mongoose");
const userSchema = new mongoose.Schema(
{
firstName: { type: String, required: true, maxlength: 256 },
lastName: { type: String, required: true, maxlength: 256 },
username: {
type: String,
lowercase: true,
unique: true,
required: [true, "can't be blank"],
match: [/^[a-zA-Z0-9]+$/, "is invalid"],
index: true,
},
password: { type: String, required: true, maxlength: 256 },
age: { type: Number },
email: {
type: String,
lowercase: true,
unique: true,
required: [true, "can't be blank"],
match: [/\S+#\S+\.\S+/, "is invalid"],
index: true,
},
},
{ timestamp: true }
);
const Users = mongoose.models.users || mongoose.model("users", userSchema);
export default Users;
I tried deleting and recreating the user part of the db and even rewriting the schema.
I currently have the same code working for my blog posts part of the db, so I don't think its the connection api
any help would be appreciated, please explain it like you would to a 10 year old
Ive been learning to code for a few month. thank you
Try and understand what the error message is saying: you're trying to access a property users on something that's undefined.
So that suggests that mongoose.models is undefined, because that's where you're trying to access that users property.
Since mongoose.models isn't even documented, I would suggest not using it and just use documented methods of retrieving a model:
const Users = mongoose.model("users", userSchema);
var questionSchema = new Schema({
category: { name:
{
type: String,
lowercase: true,
required: [true, 'Category is a required field']
},
question:[
{
q: {
type: String,
lowercase: true
},
options: {
option1:{
type: String,
lowercase: true
},
option2:{
type: String,
lowercase: true
]
},
option3:{
type: String,
lowercase: true
},
option4:{
type: String,
lowercase: true
},
},
ans: {
type: String,
lowercase: true
},
level:{
type: String,
lowercase: true
}
}
]
},
},
{
strict: true,
runSettersOnQuery: true,
timestamps: {
createdAt: 'created', updatedAt: 'updated'
}
});
This is my question schema. I am trying to get all the questions of a particular category. Till now I have tried this ---
function (req,res,next) {
console.log(req.params.qcategory);
Question.find({
category:{
name: req.params.qcategory,
}
},'', function (err,data) {
if (err) {
err.status = 406;
return next(err);
}
console.log(data);
return res.status(201).json({
message: ' success.',data:data
})
})
};
In req.params.qcategory it contains the name of the category like 'programming' for instance.
But it returned me an empty array. **PS. There are questions of programming category in my DB. Then What am i doing wrong ???
Also is there a way to first check what category a question is and then add to the question array inside that particular category. I don't want to add questions with categories again and again instead i want to check if that category already exists in the database and push the question inside the array of that question category. For instance if a question is of 'programming' category and in the database there is already a question which is of again a 'programming' category then push the question inside the array of programming category.
If my questions are not clear then please comment I will respond quickly.
Try this, Not tested
function (req,res,next) {
console.log(req.params.qcategory);
Question.find({
"category.name": req.params.qcategory,}
, function (err,data) {
if (err) {
err.status = 406;
return next(err);
}
console.log(data);
return res.status(201).json({
message: ' success.',data:data
})
})
};
Replace the
{category:{name:req.params.qcategory}} with {"category.name":req.params.qcategory}.
read more on mongodb's Query Embedded Documents https://docs.mongodb.com/.../method/db.collection.find/
Try this.
function (req,res,next) {
console.log(req.params.qcategory);
const name = req.params.qcategory;
Question.find({name})
.then((data)=>return res.status(201).json({message:"success",data:data})
.catch(err=> {
res.status(406)
return next(err);
})
};
I have a simple user model:
{
_id: "59d72070d9d03b28934b972b"
firstName: "first"
lastName: "last"
email: "first.last#gmail.com"
subscriptions: {
newsletter: true,
blog: true
}
}
I'm trying to do partial updates on the subscriptions object. I'm passing the id of the user and a payload object that can have either one or both properties of the object. Let's say I only want to update newsletter and set it to false. I'll send:
{ id: "59d72070d9d03b28934b972b", payload: { newsletter: false } }
And then:
const user = await User.findByIdAndUpdate(
args.id,
{ $set: { subscriptions: args.payload } },
{ upsert: true, new: true }
);
This will return:
subscriptions: {
newsletter: false
}
Is there a way to only modify the newsletter property when I only pass newsletter in the payload object without deleting the other properties? I know I only have two properties in this example, but in time, the object will keep expanding.
To update only the nested field, use { "subscriptions.newsletter": false } :
const user = (await User.findByIdAndUpdate(
args.id, {
$set: {
"subscriptions.newsletter": args.payload
}
}, {
new: true
}
));
If your input can have missing fields, you can build a dynamic query in $set with only the fields you have specified in your input :
async function save(id, query) {
const user = (await User.findByIdAndUpdate(
id, {
$set: query
}, {
new: true
}
));
console.log(user);
}
var id = mongoose.Types.ObjectId("59d91f1a06ecf429c8aae221");
var input = {
newsletter: false,
blog: false
};
var query = {};
for (var key in input) {
query["subscriptions." + key] = input[key];
}
save(id, query);
I ended up doing the following:
const user = await User.findById(args.id);
// merge subscriptions
user.subscriptions = Object.assign({}, user.subscriptions, args.payload);
return user.save();
This may seem like a vague question, but I'm going to try to explain the best I can. As a side note, I'm quite new to using mongoose :)
I have a mongoose-schema storing different values for each user, like so...
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: String, required: false }],
});
The "files"-key contains an array of values, lets say for example:
userSchema.files = [value1, value2, value3]
And I want each value to be connected to some kind of ID, so that when I call the specified ID, I get the specified value. Just for demonstrating purposes, it could look something like this:
userSchema.files = [{value:value1, id: id1},
{value:value2, id: id2},
{value:value3, id: id3}]
Then I want to find the specified id, and return it's "value"-key in a request:
router.route("/home/:id")
.get(restrict, function(req, res) {
User.findOne({ user: req.session.Auth.username }, function(error, data) {
data.files.forEach(function(file) {
if (file.id === req.params.id) {
response.render("../home", file.value)
}
}
});
});
How can I do this? Tried pushing an object to files, but that didn't work as expected. Read something about ObjectId, but couldn't quite understand it. Any tips?
I think you simply need to create a separate model for File and connect it to your User model using the 'ref' keyword :
let fileSchema = mongoose.Schema({
_id : Number,
value : String
});
let userSchema = mongoose.Schema({
user: { type: String, required: true, unique: true },
pass: { type: String, required: true },
files: [{ type: Number, ref: 'File' }]
});
let User = mongoose.model('User', userSchema);
let File = mongoose.model('File', fileSchema);
let f1 = new File({ _id: 1, value: 'File 1'});
let f2 = new File({ _id: 2, value: 'File 2'});
let f3 = new File({ _id: 3, value: 'File 3'});
let user1 = new User({user:'chuck', pass:'norris'});
user1.files.push(f1);
user1.files.push(f2);
user1.files.push(f3);
user1.save(function(err){ });
Now to get the data back:
User
.findOne({ user: 'chuck' })
.populate('files') // only works if we pushed refs to children
.exec(function (err, user) {
if (err) return handleError(err);
console.log(user);
//you can now loop through user.files and compare _id
user.files.forEach(function(file) {
if (file._id === req.params.id) {
response.render("../home", file.value)
}
}
});
You can read about mongoose reference population here: http://mongoosejs.com/docs/populate.html
I am trying to save template based on user id , How can i make sure when template save it save with user id _id ? i added reference to the templateSchema for User.
user.model.js
var UserSchema = new mongoose.Schema({
_id: { type: String, required: true, index: {unique: true}},
firstName: String,
lastName: String,
type: String,
groups:[{type: String, ref: 'Group', required: false}]
},
{
toObject: {
virtuals: true
},
toJSON: {
virtuals: true
}
});
export default mongoose.model('User', UserSchema);
template.model.js
var User = require('../user/user.model.js');
var TemplateSchema = new mongoose.Schema({
_id: { type: String, required: true},
name: String,
id: String,
appliesTo: [],
properties: [],
createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User'}
});
export default mongoose.model('Templates', TemplateSchema);
template.controller.js
var eTemplate = require('./template.model');
export function create(req, res) {
console.log(req.body);
eTemplate.createAsync(req.body)
.then(responseWithResult(res, 201))
.catch(handleError(res));
}
Mongoose has two built-in functions that are called before (pre) and after (post) you save a document. My advice is to make use of them. Here is an example of my code in which I search for an sequence number before saving the user document. You can do the same: When you save the template, make a request for the user id to the database (Or vice-versa). You can even save one, get the id and save the other.
Bellow follows my code for the sequence and the user.
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
id: { type: String },
...
});
UserSchema.pre('save', function(next) {
let doc = this;
let id = 'userSeq'
Sequence.findByIdAndUpdate(id, { $inc : {nextSId : 1} }, function(error,data) {
if(error)
next(error)
doc.id = data.nextSId-1;
next();
})
});
I hope my answer was useful for you. Just a remark, pre and post are not called in the event of updates for the document.