Inability to pull from a nested array - javascript

I have this query
router.delete('/:_id', async (req, res) => {
const {_id} = req.params;
const errors = [];
console.log(_id);
await Promise.all([
// Pon.findOneAndDelete({_id}).catch((e) => {
// console.log(e);
// errors.push('Something went wrong. Pon was not deleted');
// }),
// ^^^^^^^^^ this part worked. Wanted to just test the other query
User.findOneAndUpdate({_id: req.user._id}, {$pull: {pons: {_id}}}).catch((e) => {
console.log(1, e);
errors.push('Something went wrong. Pon reference was not deleted from user');
}),
]);
if (errors.length > 0) {
console.log(2, errors);
res.json({ok: false, errors});
} else {
res.json({ok: true});
}
});
I am just trying to remove an element from user object. Here's the object
{
"_id": {
"$oid": "5ea2d8cffe35b93e84f7962b"
},
"pons": [
{
"$oid": "5ea98b181a2be04ec87aa710" // this is what I want to remove
}
],
"email": "test#test.tes",
"password": "$2a$12$VJ0MkcGUs42pikT42qLpyOb0Sd53j9LXH8dY9RdR/GcmUVzJoP8gi",
"__v": 0
}
This query doesn't throw any errors, catch doesn't catch anything, so I don't know what I'm doing wrong. I tried just doing {pons: _id} instead of {pons: {_id}} but no luck.
The _id is correct. Checked with console.log.
What am I missing?

_id is just a String. If you want to match an ObjectId, you have to wrap it like this mongoose.Types.ObjectId(_id)
const ObjectId = mongoose.Types.ObjectId
User.findOneAndUpdate(
{ _id: ObjectId(req.user._id) },
{ $pull: { pons: ObjectId(_id) } }
)
Since you are querying by _id, you could also use User.findByIdAndUpdate() which will wrap req.user._id with ObjectId for you.
const ObjectId = mongoose.Types.ObjectId
User.findByIdAndUpdate(req.user._id, { $pull: { pons: ObjectId(_id) } })

Related

Node Js: Remove string array element from mongoDB

I have a user schema as follows:
const UserSchema = new mongoose.Schema({
skills: [String]
});
module.exports = mongoose.model("User", UserSchema);
And a Fetch request to delete a skill as follows:
const deleteItem = async (id) => {
try {
await fetch(`http://localhost:5000/api/user/deleteskill`, {
method: "DELETE",
headers: { "Content-Type": "application/JSON", token: accessToken },
body: JSON.stringify({ userid: userid , skill:id}),
})
.then((res) => res.json())
.then((data) => {
console.log("USER SKILLS:", data.userskills);
});
} catch (err) {
console.log(err);
}
};
Server
const deleteSkill = async (req, res) => {
try {
const user = await User.findById(req.body.userid)
//user.skills.pull(req.body.skill);
// removeskill = user.skills.filter(function(item) {
// return item !== req.body.skill
// })
if (user.skills.includes(req.body.skill)) {
res.status(400).json("Item Still Exists");
} else {
res.status(200).json("Item Deleted");
}
} catch (error) {
res.status(500).send({ error: error.message });
}
};
the array is in the following structure
[
'skill1', 'java', 'skill5'
]
I have tried to remove the user skill from the array in several ways but I still get res.status(400).json("Item Still Exists");. What I'm doing wrong?
Use the findOneAndUpdate method to find a document with the user id and update it in one atomic operation:
const deleteSkill = async (req, res) => {
try {
let message = "Item Deleted";
let status = 200;
const user = await User.findOneAndUpdate(
{ _id: req.body.userid },
{ $pull: { skills: req.body.skill } },
{ new: true }
)
if (user && user.skills.includes(req.body.skill)) {
message = "Item Still Exists";
status = 400;
} else if (!user) {
message = "User Not Found";
status = 404;
}
res.status(status).send({ message });
} catch (error) {
res.status(500).send({ error: error.message });
}
};
I believe you want to remove skills from the database then the following function could help you out.
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("mydb");
var myquery = { userid: userid, skillid: skillid};
dbo.collection("skills").deleteOne(myquery, function(err, obj) {
if (err) throw err;
console.log("1 document deleted");
db.close();
});
});
You have a method of removing elements from arrays, if you want to remove the first one you could use array.shift (more on it here), but if you want to delete it completely from your database you could always, find it and then update it.
User.update({ _id: userid }, { $pull: { "skills": "[skill]" }})

Update a nested array in a nested array

I am trying to update using this route.
router.put("/:id", async(req,res)=>{
try {
const updateUser = await User.findByIdAndUpdate(req.params.id, {
$push: {
clients:{
client_name: req.body.client_name,
client_Username: req.body.client_Username,
client_Password: req.body.client_Password,
documents : [
{
name : req.body.docName,
descritption : req.body.docDescription,
doc_upload : req.body.doc_upload,
}
]
}
}
},{new:true})
res.status(200).json(updateUser);
}
catch(err) {
res.status(500).json(err);
}
});
Once the function founds the id it updates client_name, client_Username and client_password without any issue.
My problem is when I try to update the nested array documents with a name/description and doc_upload. I am not able to do that.
What’s wrong ? How to do it please ?
One solution could be to separate the updates:
router.put('/:id', async (req, res) => {
try {
const { id } = req.params;
const { client_name, client_Username, client_Password } = req.body;
const updateUser = await User.findByIdAndUpdate(
id,
{
$push: {
clients: {
client_name,
client_Username,
client_Password,
},
},
},
{ new: true }
);
await User.findOneAndUpdate(
{
id,
'clients.client_name': client_name,
'clients.client_Username': client_Username,
},
{
$push: {
'clients.$.documents': {
name: req.body.docName,
descritption: req.body.docDescription,
doc_upload: req.body.doc_upload,
},
},
}
);
res.status(200).json(updateUser);
} catch (err) {
res.status(500).json(err);
}
});

Error in updating profile with image using mongoose and cloudinary

updateProfile: async function(req, res) {
try {
const update = req.body;
const id = req.params.id;
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
const image = req.files.profileImage;
const cloudFile = await upload(image.tempFilePath);
const profileImage = cloudFile.url
console.log('Loging cloudfile', profileImage)
await User.updateOne(id, { update }, { profileImage }, { new: true },
function(err, doc) {
if (err) {
console.log(err)
}
if (doc) {
return res.status(200).send({ sucess: true, msg: 'Profile updated successful' })
}
});
} catch (error) {
res.status(500).json({ msg: error.message });
}
}
But I'm getting an error of "Callback must be a function, got [object Object]"
I have tried to $set: update and $set: profileImage but still not working.
So the image successful upload into the cloudinary but the update for mongoose is not working.
Upon brief research into the issue, I think you are feeding the arguments in wrong. Objects can be confusing but not to worry.
Your code is:
await User.updateOne(id, { update }, { profileImage }, { new: true }
However, I believe it should be something more like:
await User.updateOne({id: id}, { profileImagine: profileImage, new: true },
The API reference annotates use of the function as:
const filter = { name: 'John Doe' };
const update = { age: 30 };
const oldDocument = await User.updateOne(filter, update);
oldDocument.n; // Number of documents matched
oldDocument.nModified; // Number of documents modified

how to remove an object inside the array of objects in mongodb

I want to remove an object inside the array of objects and I am doing this
router.post("/delVendAttach", async (req, res) => {
try {
let vend = await Vendors.findOneAndUpdate({ "level1.email": req.body.email }, {
$pull: {
"level2.attachments": {
_id: req.body.id
}
}
})
return res.status(200).send("Attachment Deleted Successfully");
} catch (error) {
console.log("error", error);
return res.status(400).send(error);
}
});
Here is the img of db collection
I think you find from level1.email and remove from level2 that the problem.
Try below code may be works for you !
let vend = await Vendors.findOneAndUpdate({ "level1.email": req.body.email }, {
$pull: {
"level1.attachments": {
_id: req.body.id
}
}
})
Duplicate of Using $pull in Mongodb to remove a deeply embedded object

How to architect array of promises in GraphQL resolver with multiple API calls to return a single object type list

I'm stuck in my GraphQL resolver fetching todo-lists for a particular user belonging to a company. According to whether or not they have access to all todo-lists or a certain few, it will fetch for groups the user registered to that have belonging todo-lists, and those should be fetched.
The code so far is capable of logging the requested todo-lists on the query but I have yet to come to the solution on how to actually return data of all of the user's registered groups's todo-lists.
I chose to export the actual logic into a separate function
The Resolver:
allowedListItems: {
type: new GraphQLList(TodoItem),
resolve(parentValue, args) {
return Promise.all([fetchAllowedItems(parentValue._id)]);
}
},
The Promise Function
function fetchAllowedItems(userId) {
return User.findOne({ _id: userId }).then((user) => {
if (user.todoGroups) {
return user.todoGroups.map((groupId) => {
return TodoGroup.findOne({ _id: groupId }).then(group => {
return group.todoLists.map((listId) => {
return TodoList.findOne({ _id: listId })
})
})
})
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
})
}
I am not getting any errors from GraphQL so I guess it's about the way I make the promisses return to the resolver, I'd appreciate a lot if you can help me out!
Update:
I should wrap the maps with a Promise.all, as the mapping returns an array.
Though the updated code brings no improvement in the returned data.
async resolve(parentValue, args) {
let user = await User.findOne({ _id: parentValue._id })
if (user.todoGroups) {
return Promise.all(user.todoGroups.map((groupId) => {
return TodoGroup.findOne({ _id: groupId }).then(group => {
return Promise.all(group.todoLists.map((listId) => {
return TodoList.findOne({ _id: listId });
}))
})
}))
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
}
},
Current query result:
{
"data": {
"user": {
"_id": "5ba11690ad7a93d2b34d21a9",
"allowedTodos": [
{
"_id": null,
"title": null
}
]
}
}
}
You need to call Promise.all on an array of promises, not a promise for that. Also you'll have to call it on each level:
allowedListItems: {
type: new GraphQLList(TodoItem),
resolve(parentValue, args) {
return User.findOne({ _id: parentValue._id }).then(user => {
if (user.todoGroups) {
return Promise.all(user.todoGroups.map(groupId => {
// ^^^^^^^^^^^^
return TodoGroup.findOne({ _id: groupId }).then(group => {
return Promise.all(group.todoLists.map(listId => {
// ^^^^^^^^^^^^
return TodoList.findOne({ _id: listId })
}));
});
}));
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
});
}
}

Categories

Resources