remove a particular array element from mongodb on clicking the element - node.js

I'm using this code for removing a particular array element stored in MongoDB when clicked that from the app. But this code is not working.
schema structure looks like this -
const tagsSchema = new Schema({
category: {
type: String,
required: true
},
tname: { type: Array }
}, { _id: true });
Below is the code I'm using for removing array element from db -
Tags.updateOne({ tname: req.params.name }, { $pull: { _id: [req.params.id] } })
For example - "tname": "technical", "nontechnical"
Now, technical is being clicked in the app to remove, but with the code I'm using it's not getting removed.

you can use directly your element_value without [] after your array field, like below..
Tags.updateOne({tname: req.params.name}, { $pull: { your_array_field: req.params.id } } )

You have to find the specific tag by its "_id" and then remove the particular name from the "tname" array.
Tags.updateOne({ _id: req.params.id }, { $pull: { tname: req.params.name } })

Related

MongoDB: add object to subarray if not exists

I searched many questions here and other articles on the web, but they all seem to describe somehow different cases from what I have at hand.
I have User schema:
{
username: { type: String },
lessons: [
{
lesson: { type: String },
result: { type: String }
}
]
}
I want to add new element into lessons or skip, if there is already one with same values, therefore I use addToSet:
const dbUser = await User.findOne({ username })
dbUser.lessons.addToSet({ lesson, result: JSON.stringify(result) })
await dbUser.save()
However it makes what seems to be duplicates:
// first run
[
{
_id: 60c80418f2bcfe5fb8f501c1,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
}
]
// second run
[
{
_id: 60c80418f2bcfe5fb8f501c1,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
},
{
_id: 60c80470f2bcfe5fb8f501c2,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
}
]
At this point I see that it adds _id and thus treats them as different entries (while they are identical).
What is my mistake and what should I do in order to fix it? I can change lessons structure or change query - whatever is easier to implement.
You can create sub-documents avoid _id. Just add _id: false to your subdocument declaration.
const userSchema = new Schema({
username: { type: String },
lessons: [
{
_id: false,
lesson: { type: String },
result: { type: String }
}
]
});
This will prevent the creation of an _id field in your subdoc, and you can add a new element to the lesson or skip it with the addToSet operator as you did.

$push into deeply nested array mongoose

my userSchema is as follows...
const userSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
movies: [
{
name: String,
duration: Number,
actors: [{ name: String, age: Number }]
}
],
});
In my NodeJS app with express I am trying to update my actors array to have another actor with value stroking from req.body.
I thought that I could do something like this...
await User.updateOne(
{
_id: req.user.id
movies._id: req.params.id
},
{
$push: { 'movies.actors': req.body }
}
)
I thought this would push an actor into the specified movie req.params.id but does nothing instead.
Try using positional operator $ in this way:
db.collection.update({
"_id": 1,
"movies._id": 1
},
{
"$push": {
"movies.$.actors": req.body
}
})
Note the only diference is the use of $. But with positional operator you are saying mongo where push the new data.
As docs says:
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
So you can update the element movies.actors pushing new data without knowin the position of the element.
Example here
Try this:
await user.updateOne(
{$and:[{_id: req.user.id},{movie.name: 'I am Legend'}]},
{$set: { movies.actors:req.body}},
);

MongoDB - update data in array of objects within object

I have a document in mongoDB structured like that
_id: ObjectId("generatedByMongo"),
name: {
required: true,
type: String,
trim: true
},
last: {
required: true,
type: String,
trim: true
},
grades: [{
grade: {
_id: ObjectId(""),
grade: Number,
date: date
}
}]
And to server I send array of objects containing 3 fields
[
{studentId}, {gradeId}, {newGrade}
]
What I'm trying to accomplish is I want to find in within that user collection grade with given gradeId and update it's value to newGrade. As far as I tried to do that I have done this
router.patch('/students/updateGrade',async(req,res) => {
const studentId = req.body.updateGradeArray[0].studentId;
const gradeId = req.body.updateGradeArray[0].gradeId;
const newGrade = req.body.updateGradeArray[0].newGrade;
try {
const student = await Student.find({_id: studentId})
.select({'grades': {$elemMatch: {_id: gradeId}}});
} catch(e) {
console.log(e);
}
}
);
If you intend to update just grade.grade(the number value), try this:
Student.updateOne(
// Find a document with _id matching the studentId
{ "_id": studentId },
// Update the student grade
{ $set: { "grades.$[selectedGrade].grade": newGrade } },
{ arrayFilters: [{ "selectedGrade._id": gradeId }] },
)
Why this should work:
Since you are trying to update a student document, you should be using one of MongoDB update methods not find. In the query above, I'm using the updateOne method. Inside the updateOne, I am using a combination of $set and $[identifier] update operators to update the student grade.
I hope this helps✌🏾

mongoose duplicate items getting inserted using $addToSet and $each to push items into the array

I am trying to push an array of objects into a document. I am using $addToSet to try and not insert duplicate data. I want to do a check on applied.studentId. But if I pass the same request twice, then the data is getting inserted. Is there any check on $addToSet and $each that I have to use?
My schema is as follows
jobId: { type: Number},
hiringCompanyId: String,
applied: [{
studentId: String,
firstName:String,
lastName:String,
gender:String,
identityType:String,
identityValue:String,
email:String,
phone:String,
}],
My node code is as follows.
public ApplyForJob(data: JobDto): Promise<{ status: string }> {
let students = data.applied;
let findQuery = {hiringCompanyId: data.hiringCompanyId, jobId: data.companyJobId};
let appliedQuery = {};
if (!isNullOrUndefined(data.applied.length)) {
appliedQuery = {
"$addToSet": {
"applied": {
"$each": data.applied
}
}
};
}
return new Promise((resolve, reject) => {
Jobs.findOneAndUpdate(findQuery, appliedQuery).exec((err, info) => {
if (err) {
reject(new UpdateError('Jobs - Update()', err, Jobs.collection.collectionName));
} else {
console.log(info);
resolve({status: "Success"});
}
})
});
}
On disabling the date field, $addToSet does not add duplicate values. As per the doc https://docs.mongodb.com/manual/reference/operator/update/addToSet/
As such, field order matters and you cannot specify that MongoDB compare only a subset of the fields in the document to determine whether the document is a duplicate of an existing array element.
as Rahul Ganguly mention absolutely correctly, we cannot use reliably $addToSet with JS objects.
One options is to move applied in to separate collection and make Job schema to ref new Applied model.
Example:
{
jobId: { type: Number },
hiringCompanyId: String,
applied: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Applied'
}]
}

Mongoose how to auto add _id to objects in array within collection item?

i have a mongo collection that looks like this:
{
name: string
_id: (auto set)
items: array[
name: string
url: string
items: array[
{
name: string,
url: string,
items: []
}
]
]
}
I'm using findByIdAndUpdate (with mongoose) to add an item into the items array:
Menu.findByIdAndUpdate(
req.body.parentid,
{
$push: {
items: {
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
},
{
safe: true,
upsert: true,
new: true
},
function(err, model) {
if (err !== null) {
console.log(err);
}
}
);
This works fine, but it does not add an _id to each object inserted into the items array. And i really need an id for each one.
I'm guessing it comes from the method used, findByIdAndUpdate as it looks more like an update rather than an insert. If my thinking is correct.
Using mongodb 3.2.10 and mongoose 4.7.6.
Any help would be really appreciated.
Thanks.
EDIT: the _id: (auto set) is not real, it's being automatically added via mongo. But just at the top level objects.
Found the solution in this thread: mongoDB : Creating An ObjectId For Each New Child Added To The Array Field
basically, added
var ObjectID = require('mongodb').ObjectID;
and then forcing the creation:
$push: {
items: {
_id: new ObjectID(),
name: req.body.item.name,
url: req.body.item.url,
items: []
}
}
You dont need to sepcify _id: (auto set) in mongoose schema it will automatically add unique _id with each document.
if you don't define _id in Schema, mongoose automatically add a _id to array item.
for example:
const countrySchema = new Schema({
name: {
type: String
},
cities: [
{
// don't define _id here.
name: String
}
],
});
now when you insert a row, the result is something like this:
{name : 'Iran', cities : [{_id : 6202902b45f0d858ac141537,name :
'Tabriz'}]}

Resources