user updates using Mongoose mongodb push not working - node.js

I am trying to use MongoDB Mongoose MongoDB push to update an entity such that the dcrLocations array gets the dcrlocation entity pushed into it
This is my response from the MongoDB server
{
acknowledged: true,
modifiedCount: 0,
upsertedId: null,
upsertedCount: 0,
matchedCount: 0
}
Heres my model code
import mongoose from "mongoose";
//User Schema
const UserSchema = new mongoose.Schema({
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
username: {
type: String,
},
email: {
type: String,
required: true,
lowercase: true,
trim: true,
unique: true,
index: true,
},
password: {
type: String,
required: true,
trim: true,
},
hasSubscription: {
type: Boolean,
default: false
},
dcrLocations: [
{
dcrLocationId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'DCRLocation'
}
},
]
},
{
toJSON: {
transform(doc, ret) {
delete ret.password,
delete ret.__v,
delete ret.createdAt,
delete ret.updatedAt
}
}
,
timestamps: true,
}
)
;
UserSchema.index({email: 1, phone: 1})
export default mongoose.model("User", UserSchema);
Heres my controller code
import {User} from "../../path/to/model.js";
import {ObjectID as ObjectId} from "mongodb";
function functionName() {
return {
AssDCRLoToUsr: async (req, res) => {
try {
const {dcrLocationId} = req.body;
console.log(dcrLocationId)
const userToUpdate = await User.updateOne(
{_id: req.params.id},
{
$push: {
dcrLocations: {
dcrLocationId: new ObjectId(dcrLocationId)
}
}
}
);
console.log(userToUpdate)
res.json(userToUpdate)
} catch (error) {
console.error(error)
res.json(false)
}
},
}
}
export {functionName};
Any advice on how I can make this work? I have been battling with it for some time now

try this
$addToSet is used to add unique element in array
import {User} from "../../path/to/model.js";
import {ObjectID as ObjectId} from "mongodb";
function functionName() {
return {
AssDCRLoToUsr: async (req, res) => {
try {
const {dcrLocationId} = req.body;
console.log(dcrLocationId)
const userToUpdate = await User.updateOne(
{_id: req.params.id},
{
$addToSet: {
dcrLocations: {
dcrLocationId: new ObjectId(dcrLocationId)
}
}
}
);
console.log(userToUpdate)
res.json(userToUpdate)
} catch (error) {
console.error(error)
res.json(false)
}
},
}
}
export {functionName};

Related

NodeJS, Mongoose prevent Push to write if same data is already in the array

I have app where I have Users. Every user can be an owner of an item or multiple items..
If user is already owner of that item prevent to push the item object into array, if already exists.
I already tried different solutions (I will write what I tried in the end of the question).
User model:
import * as mongoose from "mongoose";
const Schema = mongoose.Schema;
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, min: 6, max: 255 },
password: { type: String, required: true, min: 4, max: 1024 },
role: { type: String, required: true, default: "User" },
owners: [
{
type: Schema.Types.ObjectId,
ref: "Owners",
required: false,
},
],
});
module.exports = mongoose.model("Users", UserSchema);
Add owner to user controller:
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
console.log("here");
let ObjectID = require("mongodb").ObjectID;
const mongoose = require("mongoose");
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
const updatedUser = await User.findOneAndUpdate(
{
_id: req.params.userId,
owners: { $ne: req.body.ownerId },
},
{
$push: { owners: req.body.ownerId },
}
);
res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
} catch (err) {
res.status(404).json(err);
}
};
I already tried solutions like this, but nothing works as expected.. (check the commented code)
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
console.log("here");
let ObjectID = require("mongodb").ObjectID;
const mongoose = require("mongoose");
// add get user and find if he already has this id.. if has then json 200
// if not i execute line 230
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
/* const updatedUser = await User.findOneAndUpdate(
{ _id: req.params.userId },
{
"ownerId.ownerId": {
$ne: ObjectID(req.body.ownerId),
},
},
{
$addToSet: {
"ownerId.ownerId": ObjectID(req.body.ownerId),
},
},
{
new: true,
}
); */
const updatedUser = await User.findOneAndUpdate(
/* {
_id: req.params.userId,
},
{
$addToSet: {
owners: req.body.ownerId,
},
},
{
new: true,
} */
{
_id: req.params.userId,
owners: { $ne: req.body.ownerId },
},
{
$push: { owners: { ownerId: req.body.ownerId } },
}
);
console.log(updatedUser);
/* const updatedUser = await User.findOneAndUpdate(
{ _id: req.params.userId },
{
$push: { ownerId: { ownerId: req.body.ownerId } },
}
);
console.log(updatedUser); */
// $addToSet: { members: { name: 'something', username: 'something' } }
/*
User.findByIdAndUpdate(req.params.user_id,{$set:req.body},{new:true}, function(err, result){
if(err){
console.log(err);
}
console.log("RESULT: " + result);
res.send('Done')
});
};
*/
res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
} catch (err) {
res.status(404).json(err);
}
};

NodeJS, Mongoose if ID exists do nothing, if doesn't exist push the new one to the array

I have User model and every user can have an array of ownerId's. I want to make an API which will push a new ownerId to the array, but if this ownerId already exists, do nothing..
I have tried $addToSet but it doesn't work..
However it works with $push, but if ownerId already exists it keeps pushing the same ownerId so i have duplicates which is not OK..
User model
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, min: 6, max: 255 },
password: { type: String, required: true, min: 4, max: 1024 },
role: { type: String, required: true, default: "User" },
owners: [
{
type: Schema.Types.ObjectId,
ref: "Owners",
required: false,
},
],
});
And my NodeJS Mongoose API:
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
let ObjectID = require("mongodb").ObjectID;
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
const updatedUser = await User.findOneAndUpdate(
{ _id: req.params.userId },
{
$push: { owners: req.body.ownerId },
}
);
console.log(updatedUser);
res.status(201).json({ sucess: true, msg: "User updated sucessfully" });
} catch (err) {
res.status(404).json(err);
}
};
Thanks
$push will just push data in array, in your case you should use $addToSet
$addToSet only ensures that there are no duplicate items added to the set and does not affect existing duplicate elements.
const updatedUser = await User.findOneAndUpdate({
{ _id: req.params.userId },
'ownerId.ownerId': {
'$ne': new mongoose.ObjectID(req.body.ownerId)
}
}, {
$addToSet: {
'ownerId.ownerId': new mongoose.ObjectID(req.body.ownerId)
}
}, {
new: true
});
just remove below query
'ownerId.ownerId': {
'$ne': req.body.ownerId
}
Updated code.
const updatedUser = await User.findOneAndUpdate({
_id: req.params.userId,
}, {
$addToSet: {
'ownerId.ownerId': req.body.ownerId
}
}, {
new: true
});
OR
with ownerId Query
const updatedUser = await User.findOneAndUpdate({
_id: req.params.userId,
'ownerId.ownerId': {
'$ne': req.body.ownerId
}
}, {
$push: {
'ownerId': {ownerId: req.body.ownerId }
}
}, {
new: true
});
Try this:
exports.addOwnerToUser = async (req: Request, res: Response) => {
try {
let ObjectID = require("mongodb").ObjectID;
const user = {
email: req.body.email,
ownerId: req.body.ownerId,
};
const updatedUser = await User.findOne({
_id: req.params.userId
})
.then(user => {
if (user.ownerId[0]) {
user.ownerId[0].ownerId = req.body.ownerId;
}
})
console.log(updatedUser);
res.status(201).json({
sucess: true,
msg: "User updated sucessfully"
});
} catch (err) {
res.status(404).json(err);
}
};
Your schema design is not right, that is why $addToSet is not working for you.
so, if you want multiple owners in the user object please change your schema design to this
const UserSchema = new mongoose.Schema({
email: { type: String, required: true, min: 6, max: 255 },
password: { type: String, required: true, min: 4, max: 1024 },
role: { type: String, required: true, default: "User" },
owners: [{
type: Schema.Types.ObjectId,
ref: "Owners",
required: false,
}],
});
After this use $addToSet to add the new owner id in the user object
User.findOneAndUpdate(
{ _id: req.params.userId },
{ $addToSet: { owners: req.body.ownerId } }
)
it will not add the duplicates
For Reference: https://www.mongodb.com/docs/manual/reference/operator/update/addToSet/
Note:
As per my previous experience with this kind of work, it is better if you change the key ownerId to owners
because in general these are the owners array not the ownerId

Mongoose don't insert object into array

I have a simple express application that insets comments into posts, the issue is that the comments are never inserted but no errors are shown when post via postman it properly returns the post but with no comments.
Just try: this and this but seems to not working
This is my schema
interface PostAttrs {
userid: mongoose.Schema.Types.ObjectId;
username: string;
date: Date;
text: string;
image: string;
comments: Array<any>;
likes?: number;
}
const postSchema = new Schema<PostAttrs>({
userid: {
type: mongoose.Schema.Types.ObjectId,
required: true,
},
username: {
type: String,
required: true,
},
date: {
type: Date,
required: true,
},
text: {
type: String,
required: true,
},
image: {
type: String,
required: false,
},
comments: [
{
required: false,
date: {
type: String,
required: true,
},
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
text: {
type: String,
required: true,
},
},
],
likes: {
type: Number,
required: true,
},
});
And the API route
export const createComment = async (req: Request, res: Response) => {
try {
const postId = req.params.postId;
const userId = req.params.userId;
const comment = req.body.comment;
var commentObj = {
date: new Date(),
userId: userId,
text: comment
};
await Post.findOneAndUpdate(
{ _id: postId },
{ new: true },
{$push: {
comments: { commentObj }
}},
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
}
);
} catch (error) { }
}
What's wrong with my code?
SOLVED: The problem was the order of the parameters in the findOneAndUpdate() sentence, first the search condition, next, the value to update, and finally the statement. So I had to change this
await Post.findOneAndUpdate(
{ _id: postId },
{ new: true },
{$push: {
comments: { commentObj }
}},
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
});
to
await Post.findOneAndUpdate(
{ _id: postId },
{$push: {
comments: { commentObj }
}},
{ new: true },
(err: any, doc: any) => {
if (err) {
console.log("Something wrong when updating data!");
}
console.log(doc);
return res.status(200).send(doc);
});
When using 'await' with Mongoose's methods like findOneAnd.... the method is not run unless you explicitly do so.
Try:
await Post.findOneAndUpdate(......).exec();
Also when using the await keyword you can refactor and remove the callbacks

Update name in nested object array

I'm new to MongoDB using angular as frontend. I'm trying to update a name in nested object array.
My Schema is as follows:
const mongoose = require("mongoose");
const projectDragDropSchema = mongoose.Schema({
_idProject: mongoose.Schema.Types.ObjectId,
projectTitle: { type: String, required: true },
boards: [
{
_idBoard: mongoose.Schema.Types.ObjectId,
boardTitle: { type: String, required: false },
cards: [
{
type: new mongoose.Schema(
{
cardId: { type: mongoose.Schema.Types.ObjectId, required: true },
cardTitle: { type: String, required: false },
}
// { minimize: false }
),
required: false,
},
],
required: false,
},
],
});
module.exports = mongoose.model("ProjectDragDrop", projectDragDropSchema);
I'm trying to update the cardTitle.
I have written the multiple updates to it, but unable to find the correct one.
The Router:
router.patch(
"/updateProjectBoardCardName/:_idProject/:_id",
projectBoardsCards.updateCardName
);
The code:
exports.updateCardName = (req, res) => {
const idProject = req.params._idProject;
const boardID = req.params._id;
projectDragDropSchema
.update(
{ _idProject: idProject, "boards._id": boardID },
{ cards: { $elemMatch: { _id: req.body.params } } },
{ $set: { "cards.$.cardTitle": req.body.params } }
)
.exec()
.then((result) => {
console.log(result);
res.status(200).json(result);
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
};
Thanks in advance.

Cast to ObjectId failed for value at path for model error

This is my Profile Schema:
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
// Special field type because
// it will be associated to different user
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
status: {
type: String,
required: true,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile', ProfileSchema);
This is my view api. It doesn't work. it only return Cast to ObjectId failed for value { 'experience._id': '5edcb6933c0bb75b3c90a263' } at path _id for model profile
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findById({
'experience._id': req.params.viewexp_id,
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
How can I fix this? I tried looking at the stackoverflow of the same errors. still it doesn't seem to work.
and this is what I am trying to hit
The problem is that you have to convert your string _id to mongoose object id using this function mongoose.Types.ObjectId and my suggestion is to use findOne function instead of findById,
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
let id = mongoose.Types.ObjectId(req.params.viewexp_id);
const exp = await Profile.findOne(
{ "experience._id": req.params.viewexp_id },
// This will show your sub record only and exclude parent _id
{ "experience.$": 1, "_id": 0 }
);
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findOne({
'experience._id': mongoose.Types.ObjectId(req.params.viewexp_id),
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
You are saving object id . but your param id is string. convert it in ObjectId. Please check my solution.
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubuername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin,
} = req.body;
const profileFileds = {};
profileFileds.user = req.user.id;
if (company) profileFileds.company = company;
if (website) profileFileds.website = website;
if (location) profileFileds.location = location;
if (bio) profileFileds.bio = bio;
if (status) profileFileds.status = status;
if (githubuername) profileFileds.githubuername = githubuername;
if (skills) {
profileFileds.skills = skills.split(",").map((skill) => skill.trim());
}
//Build profile object
profileFileds.social = {};
if (youtube) profileFileds.social.youtube = youtube;
if (twitter) profileFileds.social.twitter = twitter;
if (facebook) profileFileds.social.facebook = facebook;
if (linkedin) profileFileds.social.linkedin = linkedin;
if (instagram) profileFileds.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFileds },
{ new: true }
);
return res.json(profile);
}
//Create profile
profile = new Profile(profileFileds);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("server Error");
}
}
);

Resources