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

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
}
}

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.

Mongoose search by array entries ($in) behavior not aligned with MongoDB Atlas

I'm running a Node.js server, connecting to a MongoDB database with mongoose.
Inside my controller, I have several methods that make operations to the database. One of them is this one:
async findMultiple(req, res) {
const [baseSkillsArray] = Array(req.body);
try {
// if there is not baseSkillsArray, skip
if (!baseSkillsArray) {
return res.status(200).send([]);
}
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({
_id: { $in: [baseSkillsArray.baseSkillArray] } //
});
console.log('test ' + allBaseSkills);
res.status(200).send(allBaseSkills);
} catch (error) {
console.error(error.message);
res.status(500).send('Server error find BaseSkills');
}
}
However, this returns me nothing. I did some debugging and I found the reason is the find id $in the array. So I tried hard coding a value, like '2', for instance.
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({ _id: { $in: ['2'] } });
No success. So I went to MongoDB Atlas, where my DB is stored. I tried filtering using the same line of code in my collections.
{ _id: { $in: ['2'] } }
Surprisingly, it returns my document as I wanted!
The issue is that I need to make it work with mongoose. Any ideas? Is this a known bug?
There is nothing wrong with the query, nor a bug regarding $in.
In fact, what's wrong is the actual collection name. I manually created a collection in MongoDB Atlas, called "baseSkills". However, mongoose by default transforms your collection name into lowercase and adds an "s" if your collection's name is not in the plural.
So every time I started my server, I noticed that there was a new collection called "baseskills". I assumed it was a bug and deleted it. Only after making this post that I realized the collection was there again.
So I exported the documents to this collection and my query was working fine.
FYI, there is a way to enforce the collection's name in mongoose. When you declare you model, add a second parameter to the Schema function called "collection". Here is an example:
const BaseSkillSchema = new mongoose.Schema({
_id: {
type: String,
required: true
}, ...
}, { collection: 'baseSkills' })
That's it! Sorry for the mess and thank you for your help!
you want to query over mongo db object ids. So you should create a new ObjectId to do that.
import {Types} from 'mongoose';
{ _id: { $in: [new Types.Object("2")] } }
Or if you have 2 ids one generated and one custom created as id then you can query without creating a new object.
{ id: { $in: ['2'] } }

Is there specific way to do an if-else statement in javascript for mongodb using mongoose?

I want to only run a statement only if the object is not null. If it is null I want to not do anything. I want to be sure if there is a proper way to achieve this. For example I tried it on MongoDB Playground and it did not work. Here is the link to playground: https://mongoplayground.net/p/yOmRxML88zi
Here is the if-else statement I want to run:
db.collection.aggregate([
{...},
service_type ? { $match: { serviceType: service_type } } : null,
{...},
]);
So if the service_type is not null run the statement else skip to next object in the aggregation. What I want to do in this occasion is get the list of everything in database (objects) that contain certain service type given by the user.
The schema looks something like this:
const sellerSchema = new mongoose.Schema({
user_id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
...,
serviceType: [{ String }],
});
If you're using Mongoose, I suppose you're writing your app using Javascript or TypeScript.
What prevent you, then, from building your query like this?
const aggregatePipeline = [];
if (service_type) aggregatePipeline.push({ $match: { serviceType: service_type }});
...
db.collection.aggregate(aggregatePipeline).exec()

mongodb query for object properties inside array inside of an object

Datastructure:
Document:
{
"projects": {
"projectName" : String,
"employees": [String]
}
}
Now i want to find a document which has a project with name "project1" and an employee "employee1".
When i try to query by only one property from the nested projects object, it seems to be no problem.
But as soon as i want also to access the nested array. Queries start to fail.
db.documents.find({'projects': { $elemMatch: { name: "project1", $elemMatch: { employees: 'employee1' } } })
I work with meteor collections, so it looks like this:
Documents.findOne({'projects': { $elemMatch: { name: "project1", $elemMatch: { employees: 'employee1' } } })
I also tried this simple approach:
db.collection.find({
"projects.projectName": "project1",
"projects.employees": "employee1"
})
but it didn't work.
EDIT: As J.F. suggested. This Query is correct. But i had a Schema Error. After correcting it, everything worked fine.
You can use the $in operator
https://docs.mongodb.com/manual/reference/operator/query/in/
db.collection.find({
"projects.projectName": "project1",
"projects.employees": {$in: ["employee1"]}
})

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

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

Categories