How to delete an item in an array using Mongoose/Node.js - javascript

So I've read and tried to implement the other solutions for this. I'm just trying to get some insight into why it's not working for me. This is my first project with back end work. I'm working my way through a course but wanted to try something on my own to make the concepts stick.
Here is my Schema
//ANIMAL
var animalSchema = new mongoose.Schema({
image: String,
name: String,
variety: String,
DOB: Date,
logs: [{
amount: Number,
notes: String,
dateMilked: Date
}],
created: { type: Date, default: Date.now }
});
So far I've managed to get all of my RESTful routes for animals and logs working except to delete a log.
This is what I have, but it isn't deleting anything - it also doesn't throw any errors.
app.delete("/animals/:id/logs/:id", function(req, res) {
Animal.findOneAndUpdate({ 'logs._id': req.params.id }, {
$pull: {
"logs": { "_id": req.body.id }
}
}, { safe: true, multi: true },
function(err, foundAnimal) {
if (err) {
console.log(err);
res.redirect("/");
}
else {
res.redirect("/animals/" + foundAnimal._id + "/logs");
}
});
});
Any help or insight would be great!! I'm looking to learn!

I think the problem is req.body.id probably doesn't have any value, because you are sending both ids in the path.
And if you call them the same app.delete("/animals/:id/logs/:id", I'm pretty sure req.params.id is going to have one of two values, but you are not going to be able to get the other one.
You should call them with different names, like this:
app.delete("/animals/:animalId/logs/:logId",
and then you can access to both variables without any collision:
req.params.animalId
req.params.logId
Hope it helps

Related

Mongoose - Deleting documents is unresponsive

I'm trying to use Mongoose (MongoDB JS library) to create a basic database, but I can't figure out how to delete the documents / items, I'm not sure what the technical term for them is.
Everything seems to work fine, when I use Item.findById(result[i].id), it returns a valid id of the item, but when I use Item.findByIdAndDelete(result[i].id), the function doesn't seem to start at all.
This is a snippet the code that I have: (Sorry in advance for bad indentation)
const testSchema = new schema({
item: {
type: String,
required: true
},
detail: {
type: String,
required: true
},
quantity: {
type: String,
required: true
}
})
const Item = mongoose.model("testitems", testSchema)
Item.find()
.then((result) => {
for (i in result) {
Item.findByIdAndDelete(result[i].id), function(err, result) {
if (err) {
console.log(err)
}
else {
console.log("Deleted " + result)
}
}
}
mongoose.connection.close()
})
.catch((err) => {
console.log(err)
})
I'm not sure what I'm doing wrong, and I haven't been able to find anything on the internet.
Any help is appreciated, thanks.
_id is a special field on MongoDB documents that by default is the type ObjectId. Mongoose creates this field for you automatically. So a sample document in your testitems collection might look like:
{
_id: ObjectId("..."),
item: "xxx",
detail: "yyy",
quantity: "zzz"
}
However, you retrieve this value with id. The reason you get a value back even though the field is called _id is because Mongoose creates a virtual getter for id:
Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field cast to a string, or in the case of ObjectIds, its hexString. If you don't want an id getter added to your schema, you may disable it by passing this option at schema construction time.
The key takeaway is that when you get this value with id it is a string, not an ObjectId. Because the types don't match, MongoDB will not delete anything.
To make sure the values and types match, you should use result[i]._id.

How to remove a element from an Array in Mongoose/MongoDB?

I have a small, yet important issue with my code that uses Mongoose/MongoDB. I can't seem to be able to use $pull or $pullAll in Model.findOneAndUpdate({}).
My code is the following:
db?.updateOne({ $pull: {
AutoRole: {
Roles: [value],
}
}
});
And this is my Model schema:
const guildSchema = new mongoose.Schema({
GuildID: String,
AuditChannel: String,
AutoRole: {
Roles: Array
},
});
So far I'm out of ideas on how to make it work. I was wondering if I was doing it wrong, but I can't seem to find what I'm doing exactly wrong.
I think the correct syntax here is:
{
$pull: {
"AutoRole.Roles": value
}
}

Mongo findById() only works sometimes even when passed a valid ID

I am having a strange issue querying a Mongo DB collection. I am using findById() to get a single item that works sometimes and not others.
I have checked the id being passed to the server route and in all cases, they match perfectly with the targeted document in the collection.
Here is the basic code:
router.get("/:postId", async (req, res) => {
console.log('id : ', req.params.postId)
console.log('type: ', typeof(req.params.postId)) // id is a string
try {
const post = await Post.findById(req.params.postId).exec();
console.log('post :', post) // sometimes null
res.json(post);
} catch (err) {
res.json({ message: err });
}
});
In the above route, only certain posts will be found while others come back null. This happens regardless of whether the id passed is correct and the document exists with the exact id.
If anyone has any ideas about what could be going wrong here I'd much appreciate the help!
EDIT
I have done some more debugging and think it is something to do with the Schema for the Post model.
For example, this object will be found:
{
"tags": ["foo"],
"_id": "8394839483fhg020834903",
"title": "bar",
"content": "baz",
"isPrivate": true,
}
But this one will not because of the missing isPrivate property.
{
"tags": [],
"_id": "5e0fdc631ef5c46b285a4734",
"title": "New post",
"content": "Some content here",
}
I have tested this across multiple queries and it appears to the root of the problem.
I have tried adding
isPrivate: {
required: false
}
To the Schema but it doesn't seem to solve the issue.
Here is the full Schema
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
tags: [{ type: String }],
date: {
type: Date,
default: Date.now
},
isPrivate: {
type: Boolean
required: false
}
});
I'm not a Mongo/Mongoose expert, so any guidance would be much appreciated.
If post id match with any record it return data, otherwise it will return null. You should handle the exception
router.get("/:postId", async (req, res) => {
try {
const post = await Post.findById(req.params.postId).exec();
if(post) {
return res.json(post);
}
res.json({ message:'No Post found' });
} catch (err) {
res.json({ message: err });
}
});
You can manually check is record exists against a post id. You can use MongoDB Compass for gui browse the record
I believe the issue might be with your _id as per mongo standard _id should be a String is of 12 bytes or a string of 24 hex characters.
We can check if the _id is valid using mongoose.isValidObjectId()
I did run this check on your objects that you posted and indeed 1 is invalid while other is valid
const mongoose = require('mongoose');
console.log(`is '8394839483fhg020834903' valid - ${mongoose.isValidObjectId('8394839483fhg020834903')}`);
console.log(`is '5e0fdc631ef5c46b285a4734' valid - ${mongoose.isValidObjectId('5e0fdc631ef5c46b285a4734')}`);
It gives me
You will have to check what is modifying your ID's in the code, you can upload your schema to get a better understanding as well.

Mongoose: Incrementing my documents version number doesn't work, and I'm getting a Version Error when I try to save

When I try to save my document, I'm getting a VersionError: No matching document found error, similar to this SO question.
After reading this blog post, it seems that the problem is with the versioning of my document. That I'm messing with an array and so I need to update the version.
However, calling document.save() doesn't work for me. When I log out the document before and after the call to save(), document._v is the same thing.
I also tried doing document._v = document._v++ which also didn't work.
Code
exports.update = function(req, res) {
if (req.body._id) { delete req.body._id; }
User.findById(req.params.id, function(err, user) {
if (err) return handleError(res, err);
if (!user) return res.send(404);
var updated = _.extend(user, req.body); // doesn't increment the version number. causes problems with saving. see http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html
console.log('pre increment: ', updated);
updated.increment();
// updated._v = updated._v++;
console.log('post increment: ', updated);
updated.save(function(err) {
if (err) return handleError(res, err);
return res.json(200, user);
});
});
};
Output
pre increment: { _id: 5550baae1b571aafa52f070c,
provider: 'local',
name: 'Adam',
email: 'azerner3#gmail.com',
hashedPassword: '/vahOqXwCwKQKtcV3KBQeFge/YB0xtqOj+YDyck7gzyALA/IP7u7BfqQhlVHBQT26//XfBTkaOCK2bQXg65OzA==',
salt: 'MvzXW7D4xuyGQBJNeFRoUg==',
__v: 32,
drafts: [],
starredSkims: [],
skimsCreated: [ 5550cfdab8dcacd1a7892aa4 ],
role: 'user' }
post increment: { _id: 5550baae1b571aafa52f070c,
provider: 'local',
name: 'Adam',
email: 'azerner3#gmail.com',
hashedPassword: '/vahOqXwCwKQKtcV3KBQeFge/YB0xtqOj+YDyck7gzyALA/IP7u7BfqQhlVHBQT26//XfBTkaOCK2bQXg65OzA==',
salt: 'MvzXW7D4xuyGQBJNeFRoUg==',
__v: 32,
drafts: [],
starredSkims: [],
skimsCreated: [ 5550cfdab8dcacd1a7892aa4 ],
role: 'user' }
The issue here has to do with using __v and trying to update it manually. .increment does not actually perform an increment immediately, but it does set an internal flag for the model to handle incrementing. I can't find any documentation on .increment, so I assume it is probably for use internally. The problem stems from trying to combine .extend with an object that already has __v (there are two underscores by the way, not that document.__v++ affects the model internally anyway) in addition to using .increment.
When you use _.extend it copies the __v property directly onto the object which seems to cause problems because Mongoose cannot find the old version internally. I didn't dig deep enough to find why this is specifically, but you can get around it by also adding delete req.body.__v.
Rather than finding and saving as two steps, you can also use .findByIdAndUpdate. Note that this does not use __v or increment it internally. As the other answer and linked bug indicate, if you want to increment the version during an update you have to do so manually.
Versioning was implemented to mitigate the doc.save() by design (not Model.update etc). But if you want you can try the following instead:
{$set: {dummy: [2]}, $inc: { __v: 1 }}
However this was a confirmed-bug according to the link
Please validate your mongoose version from the milestone of the above issue.
Thanks :)

MongoError,err:E11000 duplicate key error

I have a MongoDb schema like this
var User = new Schema({
"UserName": { type: String, required: true },
"Email": { type: String, required: true, unique: true },
"UserType": { type: String },
"Password": { type: String }
});
I am trying to create a new user
This is done in NodeJs using mongoose ODM
And this is the code for creating:
controller.createUser = function (req, res) {
var user = new models.User({
"UserName": req.body.UserName.toLowerCase(),
"Email": req.body.Email.toLowerCase(),
"UserType": req.body.UserType.toLowerCase()
});
models.User.findOne({ 'Email': user.Email }, function (err, olduser) {
if (!err) {
if (olduser) {
res.send({ 'statusCode': 409, 'statusText': 'Email Already Exists' });
}
else if (!olduser) {
user.setPassword(req.body.Password);
user.save(function (err, done) {
if (!err) {
console.log(user);
res.send({ 'statusCode': 201, 'statusText': 'CREATED' });
}
else {
res.send({ 'Status code': 500, 'statusText': 'Internal Server Error' });
}
});
}
}
else {
res.send({ 'statusCode': 500, 'statusText': 'ERROR' });
}
});
};
The for creating new user,I am giving attributes and values as follows:
{
"UserName": "ann",
"Email": "ann#ann.com",
"UserType": "normaluser",
"Password":"123456"
}
And I am getting error like this:
{"Status code":500,"statusText":"Internal Server Error","Error":{"name":"MongoError","err":"E11000 duplicate key error index: medinfo.users.$UserName_1 dup key: { : \"ann\" }","code":11000,"n":0,"connectionId":54,"ok":1}}
I understand that this error is because UserName is duplicated ,but I haven't set UserName with unique constraint.Whenever I add a new row,I need only email to be unique,UserName can be repeated.How to achieve this??
#ManseUK Is probably right, that looks like UserName is a 'key' - in this case an index. The _id attribute is the "primary" index that is created by default, but mongodb allows you to have multiple of these.
Start a mongo console and run medinfo.users.getIndexes()? Something must have added an index on 'UserName'.
required: true wouldn't do that, but you might have played with other settings previously and the index hasn't been removed?
There should be an index that is blocking.
You can try the db.collection.dropIndex() method
medinfo.users.dropIndexes()
I got the similar issue on my project. I tried to clear out all the documents and the dup issue still keep popping up. Until I dropped this collection and re-start my node service, it just worked.
What I had realized is that my data-structures were changing -- this is where versioning comes in handy.
You may need to get a mongoose-version module, do a thing.remove({}, ...) or even drop the collection: drop database with mongoose
I use RoboMongo for an admin tool (and I highly recommend it!) so I just went in and right-clicked/dropped collection from the console.
If anyone knows how to easily version and/or drop a collection from within the code, feel free to post a comment below as it surely helps this thread ( and I :) ).

Categories