MongoDB $push is not actually pushing anything onto the array - node.js

I commented the line of code with // This Command Does not work where I suspect that it is breaking. In the debug log of mongoose, the output looks like this: But nothing is added to the medicineIds array in the Monday object for the DaysOfWeek schema.
The following is the debug output for DayOfWeek.findOneAndUpdate() where I push back onto the array, and am not seeing the result in my mongo database.
Mongoose: dayofweeks.insertOne({ medicineIds: [], _id: 'Monday', __v: 0 }, { session: null }) // <- response to $push
Mongoose: medicines.insertOne({ times: [ 1, 2 ], dayNames: [ 'Monday' ], _id: ObjectId("5e73d816d54b1202e15bb96b"), nam
e: 'Provolone', count: 23, __v: 0 }, { session: null })
Mongoose: dayofweeks.findOne({ _id: 'Monday' }, { projection: {} })
Mutation
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addDayOfWeek: {
type: DayOfWeekType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) }
},
resolve(parent, args) {
let dayOfWeek = new DayOfWeek({
_id: args.name,
medicineIds: new Array()
});
return dayOfWeek.save();
}
},
addNewMedicine: {
type: MedicineType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
count: { type: new GraphQLNonNull(GraphQLInt) },
times: { type: new GraphQLNonNull(GraphQLList(GraphQLInt))},
dayNames: { type: new GraphQLNonNull(GraphQLList(GraphQLString))}
},
resolve (parent, args) {
let medicine = new Medicine({
name: args.name,
count: args.count,
times: args.times,
dayNames: args.dayNames
});
args.dayNames.forEach((dayId) => {
DayOfWeek.findOneAndUpdate( // This Command Does Not Work:
// medicine._id, dayId are correct at this point of the
//code
{ _id: dayId },
{ $push: { medicineIds: medicine._id }},
{ new: true, useFindAndModify: false }
);
});
return medicine.save();
}
}
}
});
DayOfWeek Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const dayOfWeekSchema = new Schema({
_id: String,
medicineIds: [String] // I am trying to push onto this array
});
module.exports = mongoose.model('DayOfWeek', dayOfWeekSchema);
Medicine Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const medicineSchema = new Schema({
id: String,
count: Number,
name: String,
times: [Number],
dayNames: [String]
});
module.exports = mongoose.model('Medicine', medicineSchema);

await Promise.all(args.dayNames.map(dayName => {
return DayOfWeek.findOneAndUpdate({ _id: dayName }, { $push: { medicineIds: medicine._id }});
})).catch((err) => console.error(err));
return await medicine.save();
I just did that and it works. hmm.

Related

Cast to ObjectId failed for value "{ id: 61141a8345c9ba4338f2af20 }" (type Object) at path "_id" for model "LeaveTypes"

I was trying to create HRM project using Node and Mongodb (Mongoose) with leave management so for the leave I have created two documents 1. for leavetypes i.e anualLeave, maternityLeave and so on and the other one of taking care of the leave requests taken by the employees.
So here is my schemas and api requests.
// leave schema embedded in leaveTypeSchema
const mongoose = require("mongoose");
const Joi = require("joi-browser");
Joi.objectId = require("joi-objectid")(Joi);
const { branchSchema } = require("./branch");
const { employeeSchema } = require("./employee");
const { leaveTypesSchema } = require("./leaveType");
const leaveSchema = mongoose.Schema({
branch: {
type: branchSchema,
required: true,
},
employee: {
type: employeeSchema,
required: true,
},
leaveType: {
type: [leaveTypesSchema],
required: true,
},
daysRequested: {
type: Number,
required: true,
},
fromDate: {
type: Date,
required: true,
},
endDate: {
type: Date,
required: true,
},
availableDays: {
type: Number,
},
});
const Leave = mongoose.model("leave", leaveSchema);
//validation
function validateLeave(leave) {
const schema = {
branchId: Joi.objectId().required(),
employeeId: Joi.objectId().required(),
leaveType: Joi.object()
.keys({
anualLeave: Joi.object()
.keys({
id: Joi.objectId().required(),
})
.required(),
})
.required(),
daysRequested: Joi.number().required(),
fromDate: Joi.date().required(),
endDate: Joi.date().required(),
};
return Joi.validate(leave, schema);
}
module.exports.Leave = Leave;
module.exports.Validate = validateLeave;
//route to post leave requests from employees
router.post("/", async (req, res) => {
// validate
const { error } = Validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
// check if branch is valid
let branch = await Branch.findById(req.body.branchId);
if (!branch) return res.status(400).send("Invalid Branch");
// check if employee is valid
let employee = await Employee.findById(req.body.employeeId);
if (!employee) return res.status(400).send("Invalid employee");
// check if leaveType is valid
let leaveType = await LeaveType.findById({
id: ObjectID(req.body.leaveType.anualLeave.id),
});
if (!leaveType) return res.status(400).send("invalid leave Type");
// post the leave request
const leave = new Leave({
branch: {
_id: branch._id,
name: branch.name,
},
employee: {
_id: employee._id,
fullName: employee.fullName,
phoneNumber: employee.phoneNumber,
branch: {
_id: branch._id,
name: branch.name,
},
jobTitle: employee.jobTitle,
salary: employee.salary,
},
leaveType: [
{
anualLeave: {
id: leaveType.anualLeave.id,
},
},
],
daysRequested: req.body.daysRequested,
fromDate: req.body.fromDate,
endDate: req.body.endDate,
});
await leave.save();
res.send(leave);
Your document doesn't abide by the way you have created your schema.
When you are passing data to model, you have made leavetype nested inside employee
const leave = new Leave({
/**/
employee: {
_id: employee._id,
fullName: employee.fullName,
phoneNumber: employee.phoneNumber,
branch: {
_id: branch._id,
name: branch.name,
}, <- here
leaveType: [
{
anualLeave: {
id: leaveType.anualLeave.id,
},
},
],
});
whereas in the schema your leaveType is a diff. object property.
employee: {
type: employeeSchema,
required: true,
},
leaveType: {
type: [leaveTypesSchema],
required: true,
},

Updating field in Array with MongoDB and NodeJS

I'm new to backend and trying to make a shopping cart with NodeJs and MongoDb.
I tried many thing but i can't update the quantity field of a product.
This is the schema
const mongoose = require('mongoose');
const itemsSchema = mongoose.Schema(
{
prodId: String,
name: String,
price: Number,
qty: {
type: Number,
default: 1,
min: 1,
},
},
{
timestamps: true,
}
);
const cartSchema = mongoose.Schema(
{
total: {
type: Number,
},
products: [itemsSchema],
},
{
timestamps: true,
}
);
const Cart = mongoose.model('carts', cartSchema);
module.exports = Cart;
This is the controller
const Cart = require('../models/cart');
exports.postItemToCart = async (req, res) => {
const { prodId } = req.body;
Cart.updateOne(
{ 'products.prodId': prodId },
{ $inc: { 'products.qty': 1 } }
);
return res.status(200).send(Cart);
};
This is the cart
[
{
_id: '60062c7a9b0bfd350b3eb755',
__v: 3,
createdAt: '2021-01-19T00:48:58.006Z',
products: [
{
qty: 1,
_id: '6006333bd00fe96af648d308',
prodId: '1111',
name: 'Product One',
price: 24.22,
updatedAt: '2021-01-19T01:17:47.034Z',
createdAt: '2021-01-19T01:17:47.034Z',
},
{
qty: 1,
_id: '600634337f3eba6b451a26e5',
prodId: '2222',
name: 'Product Two',
price: 24.22,
createdAt: '2021-01-19T01:21:55.417Z',
updatedAt: '2021-01-19T01:21:55.417Z',
},
],
total: 48.44,
updatedAt: '2021-01-21T02:19:49.955Z',
},
];
I can change and update in the Mongoose documentation console, but i can't apply the same code on my project.
Please help :)
positional operator will help you to update the first matching array element.
Cart.updateOne(
{ 'products.prodId': prodId },
{ $inc: { 'products.$.qty': 1 } } //note dollar sign
);

Why deletion of element of embedded subdocument array using Mongoose JS isn't working?

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')
}
});

Schema with embedded discriminators in arrays not cloned properly

I have scheme with embedded discriminators, and I want to clone it. But when I've create model from this cloned schema, and try to create document, some properties, related to this discriminators are goes away.
Here the code
const mongoose = require('mongoose');
const propertiesSchema = new mongoose.Schema({
name: { type: String },
},
{ discriminatorKey: 'type', _id: false });
const collectionSchema = new mongoose.Schema({
name: { type: String },
properties: [propertiesSchema]
});
const propertiesArray = collectionSchema.path(`properties`);
propertiesArray.discriminator(`type1`,
new mongoose.Schema({ type1: String }, { _id: false })
);
propertiesArray.discriminator(`type2`,
new mongoose.Schema({ type2: String }, { _id: false })
);
const Collection = new mongoose.model('Collection', collectionSchema);
const Clone = new mongoose.model('Clone', Collection.schema.clone());
const data = {
name: "Collection",
properties: [
{ type: "type1", type1: "type1-1" },
{ type: "type2", type2: "type2-2" }
]
}
console.log(new Collection(data));
console.log(new Clone(data));
Result is:
{ _id: 5d1b583e6d2d8b519c8849b8,
name: 'Collection',
properties:
[ { type: 'type1', type1: 'type1-1' },
{ type: 'type2', type2: 'type2-2' } ] }
{ _id: 5d1b583e6d2d8b519c8849b9,
name: 'Collection',
properties: [ { type: 'type1' }, { type: 'type2' } ] }
So question is - why documents are different, and how to correctly clone, or "re-apply" discriminators on cloned scheme ?
node: v10.15.3
mongoose: 5.6.2
Issue will be fixed in version 5.6.4
Github fix commit

Populate a Nested Mongoose Object w/ a Nested Object

Working on my first project and have been stumped on this for a couple days.
I'm trying to populate an object that contains the brewery info and the single corresponding beer from the Beer model.
models.js
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var beerSchema = Schema({
breweryName: String,
beer: [{
beerName: String
}]
});
var draftlistSchema = Schema ({
userName: String,
tap: [{
tapNo: Number,
_tapBeer: { type: Schema.Types.ObjectId, ref: 'Beer' },
tapStatus: String
}]
});
var Draftlist = mongoose.model('Draftlist', draftlistSchema);
var Beer = mongoose.model('Beer', beerSchema);
module.exports = {
Draftlist: Draftlist,
Beer: Beer
}
route.js
var getDraftlist = function(user, callback) {
models.Draftlist.findOne({ 'userName': user }).populate( {
path: 'tap._tapBeer',
model: 'Draftlist'
}).exec(function(err, draftlist) {
// console.log(draftlist.tap)
console.log(draftlist);
callback(draftlist);
});
};`
I'm getting a null returned with the current code. Ideally I would like the returned object to look something like--
{
breweryName: Some Brewery,
beer: {// Beer object that was referenced by Id //}
}
Draftlist Object w/ null return
{ _id: 590bd0615a190204fca6d467,
userName: 'A New User1',
__v: 1,
tap:
[ { tapNo: 1,
_tapBeer: null,
tapStatus: 'onTap',
_id: 590bd0615a190204fca6d46d },
{ tapNo: 2,
_tapBeer: null,
tapStatus: 'onTap',
_id: 590bd0615a190204fca6d46c },
{ tapNo: 3,
_tapBeer: null,
tapStatus: 'onTap',
_id: 590bd0615a190204fca6d46b },
{ tapNo: null,
_tapBeer: null,
tapStatus: 'Cellar',
_id: 590bd0615a190204fca6d46a },
{ tapNo: null,
_tapBeer: null,
tapStatus: 'Cellar',
_id: 590bd0615a190204fca6d469 },
{ tapNo: null,
_tapBeer: null,
tapStatus: 'Cellar',
_id: 590bd0615a190204fca6d468 },
{ _tapBeer: null,
tapStatus: 'Cellar',
_id: 590bd0735a190204fca6d470 } ] }
Beer Object
{ breweryName: 'Beachwood',
_id: 590bd3f1ed13510514405cba,
beer: [ { beerName: 'IPA', _id: 590bd3f1ed13510514405cbb } ] }
Use mongoose-deep-populate
const
mongoose = require('mongoose'),
deepPopulate = require('mongoose-deep-populate')(mongoose);
Schema = mongoose.Schema;
const
BeerSchema = Schema({
breweryName: Schema.Types.String,
beer: [{
beerName: Schema.Types.String
}]
}),
DraftlistSchema = Schema ({
userName: Schema.Types.String,
tap: [{
tapNo: Schema.Types.Number,
_tapBeer: {
type: Schema.Types.ObjectId,
ref: 'Beer'
},
tapStatus: Schema.Types.String
}]
});
DraftlistSchema.plugin(deepPopulate);
var Draftlist = mongoose.model('Draftlist', DraftlistSchema);
var Beer = mongoose.model('Beer', BeerSchema);
module.exports = {Draftlist, Beer};
usage:
const getDraftlist = (userName, callback) => {
models
.Draftlist
.findOne({
userName
})
.deepPopulate('tap._tapBeer')
.exec((err, draftlist) => {
console.log(draftlist);
callback(draftlist);
});
};
or:
const Draftlist = models.Draftlist;
const getDraftlist = (userName, callback) => {
Draftlist
.findOne({
userName
})
.exec((err, draftlist) => {
Draftlist
.deepPopulate(
draftlist, 'tap._tapBeer',
(err, draflist) => {
console.log(draftlist);
callback(draftlist);
});
});
};

Resources