Here I have mongoose schema
const mongoose = require('mongoose');
const cartSchema = new mongoose.Schema({
items: {
type: [{
id_item: String,
cnt: Number
}],
default: [],
required: true
},
dateExpires: Date
})
cartSchema.pre('save', async function(next) {
this.dateExpires = Date.now() + 7 * 24 * 60 * 60 * 1000;
})
const modelCart = mongoose.model('Cart', cartSchema);
module.exports = modelCart;
I'm calling this function below in one of the routes to create a model, if I send empty value it should return empty array and date in database, but what it returns me is undefined, default value does not trigger. I'm new in Node.js what could be an issue ?
exports.createCart = catchAsync(async (req, res, next) => {
let newCart = await cartModel.create();
console.log(newCart); //undefined, wanted items: [], date: ...
res.status(200).json({
status: "success",
data: {
cart: newCart
}
})
})
Are you sure that you are defining that schema corectly?
Type is a special property in Mongoose schemas.
I think that it should look more like this.
const cartSchema = new mongoose.Schema({
items: {
type: Array,
nested: {
id_item: { type: String },
cnt: { type: Number }
}
default: [],
required: true
},
dateExpires: Date
})
Related
I want to update array of objects - profiles by using input
I use express,mongoose in reactjs. I have schema --
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const validator = require("validator");
const { ObjectId } = mongoose.Schema.Types;
const userSchema = new mongoose.Schema({
email:{
type: String,
required: true,
minlength: 4,
unique: true,
validate: {
validator(email) {
return validator.isEmail(email);
},
},
},
password:{
type: String,
required: true,
minlength: 5,
select: false,
},
profiles:[ // array of user's profile
{
type:ObjectId,
name:String,
}
]
})
this is my route ---
router.post('/createProfile', createProfile);
what i tryed ---
module.exports.createProfile = (req,res) =>{
const {name} = req.body;
console.log(name)
User.push(profiles,name)
.then((result)=>res.send(result))
.catch((err)=>console.log(err))
}
I dont know what the coreect way to use push. Do i need to use push? Is my chema for profiles OK?
First, you specified in your schema that profiles field is of type array of ObjectIds. It looks like you want it to be of type String instead, since you are trying the push the name inside.
So, you should first change your Schema model:
profiles:[ // array of user's profile
{
type: String,
}
]
Now, you can push new items to that array like this:
User.updateOne(
{ _id: req.user._id },
{ $push: { profiles: name } }
)
you can use the %push operator in moongose
module.exports.createProfile = (req, res) => {
const { name } = req.body;
User.findOneAndUpdate(
{ _id: req.user._id },
{ $push: { profiles: { name } } },
{ new: true, useFindAndModify: false }
)
.then((result) => res.send(result))
.catch((err) => console.log(err))
};
the findOneAndUpdate function is used to find user. and update it .as you asked
1.) I have two models: Project and Action:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ProjectSchema = new Schema({
_id: Schema.Types.ObjectId,
title: { type: String, default: "default project title" },
deadline: { type: Date, default: "2099-01-01T10:30" },
description: { type: String, default: "default project description" },
actions: [],
});
module.exports = mongoose.model("Project", ProjectSchema);
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const ActionSchema = new Schema({
_id: Schema.Types.ObjectId,
type: { type: String, default: "none" },
queued: { type: Boolean, default: false },
description: { type: String, default: "default description" },
complete: { type: Boolean, default: false },
waitingFor: [],
setting: { type: String, default: "default setting" },
deadline: {type: Date, default: "2099-01-01T10:30"}
});
module.exports = mongoose.model("Action", ActionSchema);
2.) I have a service to destroy an Action which should both update Project actions subdocument array (i.e. delete the action) and delete the Action from its collection.
It receives an id of the Action to delete from the array.
3.) I've tried several approaches but the closest I've gotten is:
require("../db");
const mongoose = require("mongoose");
const Action = require("../models/action");
const Project = require("../models/project");
const destroy = async (id) => {
const filter = { _id: id };
const action_id = mongoose.Types.ObjectId(id);
const project_id = mongoose.Types.ObjectId("5fdcd4fdc0d61b7fe59f0940");
Project.updateOne(
{},
{
$pull: { actions: { _id: id } },
},
{
arrayFilters: [{ "i._id": mongoose.Types.ObjectId(id) }],
new: true,
}
).then((output => console.log("output of db op: ", output)))
Action.deleteOne(filter, function (err, output) {
console.log("output of db op ", output);
});
};
The deletion of Action from its collection works but Project does not update its actions array. Currently, the output of the above is:
output of db op: { n: 1, nModified: 0, ok: 1 } (It finds Project but doesn't update!
output of db op { n: 1, ok: 1, deletedCount: 1 } (Successfully deletes from Action collection, but Project array is unmodified)
Any suggestions for how to successfully update Project is much appreciated. Thanks!
The pull operator sometimes doesn't work properly in MongoDB so you can try it with an update and provide the ids directly as objectIDs in the query. Also, you need to provide the id of the project you are trying to update in the update one.
Project.update({ _id: ObjectId(project_id ) },
{ $pull: { actions: ObjectId(action_id ) } },
{ new: true }, function (err, source) {
if (!err) {
console.log('Source log',source);
Action.deleteOne(filter, function (err, output) {
console.log("output of db op ", output);
});
}
else{
console.log('Error in deleting projects and actions')
}
});
I'm working on a project where in one model I need to set the value of a field based on another fields value. Let me explain with some code.
Destination model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const DestinationSchema = new Schema({
name: {
type: String,
required: true
},
priority: {
type: Number,
default: 0,
max: 10,
required: true
}
})
DestinationSchema.statics.getPriority = function(value) {
return this.findOne({ _id: value })
}
const Destination = mongoose.model('Destination', DestinationSchema)
exports.Destination = Destination
Task model
const mongoose = require('mongoose')
const { Destination } = require('../_models/destination.model')
const Schema = mongoose.Schema;
const TaskSchema = new Schema({
priority: {
type: Number,
required: true,
min: 0,
max: 25
},
from: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
to: {
type: Schema.Types.ObjectId,
ref: 'Destination',
required: true
},
type: {
type: Number,
required: true,
min: 0,
max: 3
}
}, {
timestamps: true
})
TaskSchema.pre('save', async function () {
this.priority = await Destination.getPriority(this.from).then(doc => {
return doc.priority
})
this.priority += await Destination.getPriority(this.to).then(doc => {
return doc.priority
})
this.priority += this.type
})
Task Controller update function
exports.update = async function (req, res) {
try {
await Task.findOneAndUpdate({
_id: req.task._id
}, { $set: req.body }, {
new: true,
context: 'query'
})
.then(task =>
sendSuccess(res, 201, 'Task updated.')({
task
}),
throwError(500, 'sequelize error')
)
} catch (e) {
sendError(res)(e)
}
}
When I create a new Task, the priority gets set in the pre save hook just fine as expected. But I'm hitting a wall when I need to change Task.from or Task.to to another destination, then I need to recalculate the tasks priority again. I could do it on the client side, but this would lead to a concern where one could just simply send a priority in an update query to the server.
My question here is, how can I calculate the priority of a Task when it gets updated with new values for from and to? Do I have to query for the document which is about to get updated to get a reference to it or is there another cleaner way to do it, since this would lead to one additional hit to the database, and I'm trying to avoid it as much as possible.
In your task schema.
you have to use pre("findOneAndUpdate") mongoose middleware. It allows you to modify the update query before it is executed
Try This code:
TaskSchema.pre('findOneAndUpdate', async function(next) {
if(this._update.from || this._update.to) {
if(this._update.from) {
this._update.priority = await Destination.getPriority(this._update.from).then(doc => {
return doc.priority
});
}
if(this._update.to) {
this._update.priority += await Destination.getPriority(this._update.to).then(doc => {
return doc.priority
});
}
}
next();
});
So I tried to migrate a new field to the mongoDB collections.
New field is a array that is filled with objects.
The migration runs and is successful, it even shows the new field when
looking the collections.
Problem comes when I try to add data to this field - it shows that the
field is undefined.
What should be done to overcome this problem?
Migration code:
exports.up = async function(db) {
await db
.collection('useractions')
.update({}, {
$set: {
history: []
}
}, {multi: true, upsert: false});
};
Code to populate the new field:
const bookId = req.body.bookId;
const timestamp = req.body.timestamp;
const userId = req.body.userId;
const container = {bookId, timestamp};
UserAction.update(
{ userId },
{$set: { history: container}},
(err, cb) => {
if(err)next({error: err});
res.status(200).json({
cb
})
})
EDIT:
Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userActionModel = new Schema({
userId: {
type: String
},
likes: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Podcast',
default: []
}],
tags: {
type: [String],
default: []
},
orderedBook: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Show',
default: []
}]
})
module.exports = mongoose.model('userAction', userActionModel);
I've got the following mongoose models:
Place.js
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const placeSchema = new Schema({
title: { type: String, require: true },
filename: { type: String, require: true },
lociSets: [{ type: Schema.Types.ObjectId, ref: 'LociSet'}]
})
module.exports = mongoose.model("places", placeSchema)
LociSet.js
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const LociSchema = require('./Locus')
const lociSetSchema = new Schema({
title: { type: String, require: true },
creator: { type: Schema.Types.ObjectId, ref: 'User' },
public: { type: Boolean, default: true },
loci: [LociSchema]
})
module.exports = mongoose.model("lociSets", lociSetSchema)
Locus.js
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const locusSchema = new Schema({
position: {
x: { type: Number, require: true },
y: { type: Number, require: true },
z: { type: Number, require: true }
}
})
module.exports = locusSchema
Problem:
I try to insert a new LociSet into the lociSet array of Place like so:
exports.createOne = async (req, res) => {
const {
title,
public = true,
loci = []
} = req.body
console.log(title,public,loci,req.user.id)
const lociSet = new LociSet({
title,
public,
loci,
creator: req.user.id
})
try {
const place = await Place.findOne({
"title": req.params.title.toLowerCase()
})
console.log(lociSet)
await lociSet.save()
await place.lociSets.push(lociSet)
await place.save()
} catch (err) {
res.status(500).send({
message: "Some error occurred while creating the loci set.", err
});
}
}
But then I get an error message saying "Cast to [undefined] failed for value \"[{\"title\":\"Test set\",\"creator\":\"5a7898c403999200c4ee3ae5\",\"public\":\"true\"}]\" at path \"lociSets\""
The LociSet model is created without problems, but it seems to break when I try to save the place model
Because lociSets is an array of ObjectId references, you may want to try the following approach:
exports.createOne = async (req, res) => {
const { title, public = true, loci = [] } = req.body
const lociSet = new LociSet({
title,
public,
loci,
creator: req.user.id
})
try {
const newLociSet = await lociSet.save()
const place = await Place.findOneAndUpdate(
{ "title": req.params.title.toLowerCase() },
{ "$push": { "lociSets" : newLociSet._id } },
{ "new": true}
)
res.status(200).json(place)
} catch (err) {
res.status(500).send({
message: "Some error occurred while creating the loci set.", err
})
}
}