How do i tell Mongoose NOT to save a field? - javascript

How do i tell Mongoose not to save the age field if it's null or undefined?
Or could i do this in Express somehow?
Express
router.put('/edit/:id', function(req, res) {
Person.findOneAndUpdate({ _id: req.params.id }, {
name: req.body.updateData.name,
age: req.body.updateData.age
}, { new: true });
})
Mongoose Schema
var PersonSchema = new Schema({
name: { type: String},
age: {type: String}
})
An explination (if u ask why i need this)
I'm using the same html template for new person and edit person. When i create a new person, Mongoose will save just the name field if i leave the age field empty. But when i use the edit template, Mongoose will always set the age field as null, even if the field is empty. I can't think of anything to stop this.

You could manage your request data before the db update, like:
router.put('/edit/:id', function(req, res) {
let update = {name: req.body.updateData.name};
if (req.body.updateData.age != "") {
update.age = req.body.updateData.age;
}
Person.findOneAndUpdate({ _id: req.params.id }, update, { new: true });
})

#Aioros, you answer gave me an idea, however i found this solution to match my issue. I'm just deleteing the null or undefined object elements before they are send to Mongoose.
let update = {
name: req.body.updateData.name,
age: req.body.updateData.age
};
if (update.age === null || update.age === undefined) delete update.age
Person.findOneAndUpdate({ _id: req.params.id }, update, { new: true });

Related

How to update the child document data in mongoose?

I need to update the value of tQuan to 15 where the tName is FBK in the stocks array. I couldn't find a correct answer yet. Please note that I'm not allowed to change the way that the schema is designed. Here's the schema.
const stockSchema = mongoose.Schema(
{
tName: {type: String},
tQuan: {type: Number}
}
)
const userSchema = mongoose.Schema(
{
name: {type: String},
balance: {type: Number},
stocks: [stockSchema]
}
);
Here's how it looks on my mongoDB compass.
MongoDB Compass
I'm required to use mongoose in my backend with express, so this is not done in CLI. Please help me figure out the answer to this question, appreciate your help.
I found the answer. I'll post it here, in case if that helps someone else.
User.updateOne({ name: 'Sam' , "stocks.tName" : "FBK"},
{
$set: {
"stocks.$.tQuan": 15
}
}, (err) => {
if(err) {
console.error(err);
} else {
console.log("successfully updated");
}
})
If stockSchema is not stored in the database seperately, I can suggest , i mean if you just want to show stockSchema as :
user{
_id:"id",
name:"example",
balance:12345,
stoks:[
{
tName:"name",
tQuan:1234,
}
]
}
at Users Services or wherever you call save ,update ..etc functions :
async function create(data) {
const model = mongoose.model('User');
let arr=[]
//tnamesArray from your form
data.tnamesArray.forEach((name)=>{
let obj={}
obj.tName=name
arr.push(obj)
})
//tQuansArray from your Form
data.tQuansArray.forEach((quan,key)=>{
return arr[key].tQuan=quan;
})
data.stocks=arr;
const instance=new model(data);
const savedInstance = await instance.save();
return savedInstance;
}

how do I query from parent model a array of other model in Mongoose?

I have two Schema for user & todo. Every todo has an owner as a user, every user has an array of todos.
// user.js
const TodoSchema = require('./todo').TodoSchema;
var UserSchema = mongoose.Schema({
name: {
type: String,
required: true
},
todos: {
type: [TodoSchema]
}
});
module.exports.UserSchema = UserSchema;
module.exports.UserModel = mongoose.model('UserModel', UserSchema);
// todo.js
var TodoSchema = mongoose.Schema({
body: {
type: String, required: true
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserModel',
required: true
}
});
module.exports.TodoSchema = TodoSchema;
module.exports.TodoModel = mongoose.model('TodoModel', TodoSchema);
I entered data like this.
var nUser = new UserModel({
name: "Alex
)};
nUser.save().then(user => {
var t = new TodoModel({
body: "my new todo",
owner: user._id
});
t.save().then();
});
But the problem is I want to get all the todos from a specific user, something like this...What is the correct way?
UserModel.findOne({name: "Alex"})
.then(user => {
// user.todos
});
P.S.
I can do this like TodoModel.find({owner: specific_user._id}), but I want it from UserModel.
Since you're asking for the proper way of doing it, I am gonna start with your User Schema. If you want to find all the todos of a user, then putting the todo documents inside an array in the User document is not required. So you should probably remove that from your schema.
After that you can use a simple aggregation to get your desired outcome.
UserModel.aggregate([
{
$match:{
name:"Alex"
}
},
{
$lookup:{
from:"todomodels",
localField:"$_id",
foreignField:"$owner",
as:"todos"
}
}
])
this will return all the todos for that user in an array of the same name.

Connect mongoose-array-values to a unique ID

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

Mongoose - delete subdocument array item

I have this little schema for users:
{
username: String,
contacts: Array
}
So for example some user's contacts will look like this:
{
username: "user",
contacts: [{'id': ObjectId('525.....etc'), 'approved': false}, {'id':ObjectId('534.....etc'), 'approved': true}]
}
Now I need to delete an item from contacts so I do:
model.findByIdAndUpdate(23, {'$pull': {
'contacts':{'id':'525.....etc'}
}});
but seems not working, no errors but it doesn't gets deleted, I just would like to return this document for the user:
{
username: "user",
contacts: [{'id':ObjectId('534.....etc'), 'approved': false}]
}
how to achieve this?
The $pull operator actually just performs the conditions on the array element on which it is operating. It seems that your question might not actually show that you are probably working with an ObjectId value that mongoose creates by default for all array fields.
So you could to your query like this, after importing the ObjectId creation method:
model.findByIdAndUpdate(23, {
'$pull': {
'contacts':{ '_id': new ObjectId(someStringValue) }
}
});
Or in fact you can actually define your "schema" a little better, and mongoose will actually "autocast" the ObjectId for you based on the "type" defined in the schema:
var contactSchema = new Schema({
approved: Boolean
});
var userSchema = new Schema({
username: String,
contacts: [contactSchema]
});
This allows mongoose to "follow the rules" for strictly typed field definitions. So now it knows that you actually have an _id field for each element of the contacts array, and the "type" of that field is actually an ObjectId so it will automatically re-cast "String" values supplied as a true ObjectId.
finaly!
MongoDB:
"imgs" : {"other" : [ {
"crop" : "../uploads/584251f58148e3150fa5c1a7/photo_2016-11-09_21-38-55.jpg",
"origin" : "../uploads/584251f58148e3150fa5c1a7/o-photo_2016-11-09_21-38-55.jpg",
"_id" : ObjectId("58433bdcf75adf27cb1e8608")
}
]
},
router.get('/obj/:id', function(req, res) {
var id = req.params.id;
Model.findOne({'imgs.other._id': id}, function (err, result) {
result.imgs.other.id(id).remove();
result.save();
});

How to set _id to db document in Mongoose?

I'm trying to dynamically create _id's for my Mongoose models by counting the documents in the db, and using that number to create the _id (assuming the first _id is 0). However, I can't get the _id to set from my values. Here's my code:
//Schemas
var Post = new mongoose.Schema({
//_id: Number,
title: String,
content: String,
tags: [ String ]
});
var count = 16;
//Models
var PostModel = mongoose.model( 'Post', Post );
app.post( '/', function( request, response ) {
var post = new PostModel({
_id: count,
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save( function( err ) {
if( !err ) {
return console.log( 'Post saved');
} else {
console.log( err );
}
});
count++;
return response.send(post);
});
I've tried to set the _id a number of different ways, but it's not working for me. Here's the latest error:
{ message: 'Cast to ObjectId failed for value "16" at path "_id"',
name: 'CastError',
type: 'ObjectId',
value: 16,
path: '_id' }
If you know what's going on, please let me know.
You either need to declare the _id property as part of your schema (you commented it out), or use the _id option and set it to false (you're using the id option, which creates a virtual getter to cast _id to a string but still created an _id ObjectID property, hence the casting error you get).
So either this:
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
});
Or this:
var Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
The first piece of #robertklep's code doesn't work for me (mongoose 4), also need to disabled _id
var Post = new mongoose.Schema({
_id: Number,
title: String,
content: String,
tags: [ String ]
}, { _id: false });
and this works for me
Create custom _id in mongoose and save that id as a mongo _id.
Use mongo _id before saving documents like this.
const mongoose = require('mongoose');
const Post = new mongoose.Schema({
title: String,
content: String,
tags: [ String ]
}, { _id: false });
// request body to save
let post = new PostModel({
_id: new mongoose.Types.ObjectId().toHexString(), //5cd5308e695db945d3cc81a9
title: request.body.title,
content: request.body.content,
tags: request.body.tags
});
post.save();
This works for me when saving new data for the schema. I used the exact code below in my project
new User(
{
email: thePendingUser.email,
first_name: first_name || thePendingUser.first_name,
last_name: last_name || thePendingUser.last_name,
sdgUser: thePendingUser.sdgUser,
sdgStatus: "active",
createdAt: thePendingUser.createdAt,
_id: thePendingUser._id,
},
{ _id: thePendingUser._id }
)

Categories