Mongo update query for modifying array field failing - mongodb

Important: Mongo Version I am using 3.4
Just Found out array filters is not available in 3.4
Any suggestion would be appreciated.
I have been trying this for days now I am trying to update particular comment text inside document. My document looks like this:
{
_id: "6ff1...<alphanumeric Id>",
name: "T-00001",
comment: [
{
_id: "6f7123....<alphanumeric Id>",
author: "6fsd...<alphanumeric Id pointing to user schema>"
text: "Hello",
edited: false
},
{
_id: "6f75323....<alphanumeric Id>",
author: "6ffgh21...<alphanumeric Id pointing to user schema>"
text: "Second Comment",
edited: false
}
]
}
What I am trying to achieve is to edit comment text here of particular comment id what my update query looks like is :
db.story.update(
{ _id: mongoose.Types.ObjectId(storyId) }, // Find that story story Id coming from body
{
$set : {
"comment.$[elem].text": "Update text with this",
"comment.$[elem].edited": true
}
},
{ "arrayFilters": [
{ "elem._id": mongoose.Types.ObjectId(commentId),
"elem.author": mongoose.Types.ObjectId(authorId)
} // Update only that comment.. Ids here coming from body
]}
)
Error Message I am getting
"errmsg" : "cannot use the part (comment of comment.$[elem].text) to traverse the element ({comment: [ { posted: new Date(1633092292670), delStatus: 0, _id: ObjectId('615702c4de4cf17dab996b4f'), by: \"User\", author: ObjectId('60ab52b1a3aa844774ca0fb3'), text: \"hello7\", edited: true }, { posted: new Date(1633699486732), delStatus: 0, _id: ObjectId('6160469e8aca585d3909708c'), by: \"User\", author: ObjectId('60ab52b1a3aa844774ca0fb3'), text: \"2021-10-08T13:24:46.671Z\" } ]})"

Found the solution god I am so bad....
db.story.update(
{
$and: [
{ _id: mongoose.Types.ObjectId(storyId)},
{ "comment._id": mongoose.Types.ObjectId(commentId)},
{ "comment.author": mongoose.Types.ObjectId(authorId)}
]
},
{
$set: {
"comment.$.text": body.text,
"comment.$.edited": true
}
}
)
With this I have a big problem whenever I hit this query it is updating some other comment until I remove the line:
{ "comment.author": mongoose.Types.ObjectId(authorId)}
Can someone please help?

Related

Issue using $pull from nested Mongoose array atomic operation

I can't seem to get this mongoose $pull operation to work at all. I have tried many solutions, but would ultimately like to use an atomic operation to achieve this as that is the design pattern in the rest of my code.
In my List schema, I have an array of Item objects. Each Item object has an array of Notes which are all string values. Creating, Reading, and Updating these Notes arrays has been no issue. But I can't seem to get the Delete functionality to work.
Schemas:
List
const listSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "Users"
},
name: {
type: String
},
items: {
type: Array,
default: [itemSchema]
}
});
Item
const itemsSchema = {
item: String,
style: String,
moved: Boolean,
notes: Array
};
Sample Document:
_id: 6186940ce10fbd7cec9fb01f
items: Array
0: Object
notes: Array
0: "Updated again x2"
1: "Test one to delete edit"
2: "New one"
_id: 6186d98dcef2ae43605becc4
item: "Test 1"
style: ""
moved: false
1: Object
notes: Array
_id: 6186d98fcef2ae43605becc5
item: "Test 2"
style: ""
moved: false
2: Object
notes: Array
_id: 6186d991cef2ae43605becc6
item: "Test 3"
style: ""
moved: false
3: Object
notes: Array
0: "Add from none"
1: "typing a really long sentence here to see what happens when I get to t..."
2: "Test"
_id: 6186d994cef2ae43605becc7
item: "Test 4"
style: ""
moved: false
user: 611083d8baed4458d8dcd273
name: "Nov-06-2021"
__v: 0
Methods:
Create
List.findOneAndUpdate(
{ "user": req.user.id, "name": list, "items._id": ObjectId(id) },
{ "$push": { "items.$.notes": newNote } },
{ new: true },
(err, newList) => {}
)
Update
List.findOneAndUpdate(
{ "user": req.user.id, "name": list, "items._id": ObjectId(id) },
{ "$set": { "items.$.notes.$[note]": newNoteText } },
{
arrayFilters: [{"note": note}],
new: true
},
(err, newList) => {}
)
Delete (not working)
List.findOneAndUpdate(
{ "user": req.user.id, "name": list, "items._id": ObjectId(id) },
{ "$pull": { "items.$.notes.$[note]": note } },
{
arrayFilters: [{"note": note}],
new: true
},
(err, newList) => {}
)
The current Delete code block is close to what I'd like my solution to look like. By all rights, and everything I've read, it should already work. Can anyone show me what will work, and possibly why this isn't currently working?
I have tried many solutions including using $in, $[], $elemMatch, and a bunch more outside the box solutions. I don't see why $push and $set work without issue, but $pull is deciding to do nothing.
The current response I get from MongoDb with this operation doesn't include an error message, but the returned newList is a null value, and no change is reflected in my DB. I am currently on the latest version of mongoose: 5.13.13.
The solution to this was to remove the $[note]from my operator as $pull requires an array to operate on, not the array object.
I definitely tried that before, before there was an issue with my request body that was coming from the front end. I wasn't using the correct syntax for an axios.delete, however, and that was my main issue.
Solution
List.findOneAndUpdate(
{ "user": req.user.id, "name": list, "items._id": ObjectId(id) },
{ "$pull": { "items.$.notes": note } },
{ new: true },
(err, newList) => {}
)
I removed $[note] as a variable because $pull operates on the entire notes array. Therefore, I no longer need the arrayFilters because it is already looking for the note variable.

Can't remove object in array using Mongoose

This has been extensively covered here, but none of the solutions seems to be working for me. I'm attempting to remove an object from an array using that object's id. Currently, my Schema is:
const scheduleSchema = new Schema({
//unrelated
_id: ObjectId
shifts: [
{
_id: Types.ObjectId,
name: String,
shift_start: Date,
shift_end: Date,
},
],
});
I've tried almost every variation of something like this:
.findOneAndUpdate(
{ _id: req.params.id },
{
$pull: {
shifts: { _id: new Types.ObjectId(req.params.id) },
},
}
);
Database:
Database Format
Within these variations, the usual response I've gotten has been either an empty array or null.
I was able slightly find a way around this and accomplish the deletion by utilizing the main _id of the Schema (instead of the nested one:
.findOneAndUpdate(
{ _id: <main _id> },
{ $pull: { shifts: { _id: new Types.ObjectId(<nested _id>) } } },
{ new: true }
);
But I was hoping to figure out a way to do this by just using the nested _id. Any suggestions?
The problem you are having currently is you are using the same _id.
Using mongo, update method allows three objects: query, update and options.
query object is the object into collection which will be updated.
update is the action to do into the object (add, change value...).
options different options to add.
Then, assuming you have this collection:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
},
{
"_id": 3
}
]
}
]
If you try to look for a document which _id is 2, obviously response will be empty (example).
Then, if none document has been found, none document will be updated.
What happens if we look for a document using shifts._id:2?
This tells mongo "search a document where shifts field has an object with _id equals to 2". This query works ok (example) but be careful, this returns the WHOLE document, not only the array which match the _id.
This not return:
[
{
"_id": 1,
"shifts": [
{
"_id": 2
}
]
}
]
Using this query mongo returns the ENTIRE document where exists a field called shifts that contains an object with an _id with value 2. This also include the whole array.
So, with tat, you know why find object works. Now adding this to an update query you can create the query:
This one to remove all shifts._id which are equal to 2.
db.collection.update({
"shifts._id": 2
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example
Or this one to remove shifts._id if parent _id is equal to 1
db.collection.update({
"_id": 1
},
{
$pull: {
shifts: {
_id: 2
}
}
})
Example

Update MongoDb collection and not rewrite it

I have a collection with the following objects:
{
...
"address": {
"addressLine1": "some address"
"city": "some city"
}
}
I need to update all objects to add address.fullName = address.addressLine1 (don't ask why :D) in cases when address exist.
I try to run this script in Robo 3T:
db.getCollection('suppliers').updateMany(
// query
{},
// update
{ $set: { address: { fullName: $address.address1 } } },
// options
{
// update only one document
"multi" : true,
// insert a new document, if no existing document match the query
"upsert" : false
}
);
I have an error
"$address isn't defined"
How should I write a script
To update address.fullName = address.addressLine1
Don't rewrite an entire object and subObject address (important)
Following this example from the MongoDB documentation, your update should be wrapped in an array like this.
db.getCollection('suppliers').updateMany(
{},
[
{
$set: {
'address.fullName': '$address.addressLine1',
},
},
],
{
multi: false,
upsert: false,
}
);
See a working example on MongoDB Playground

Mongoose how to use positional operator to pull from double nested array with specific condition, and return new result

Suppose I have the following schema:
{
_id: ObjectId(1),
title: string,
answers: [
{
_id: ObjectId(2),
text: string,
upVotes: [
{
_id: ObjectId(3),
userId: ObjectId(4)
}
]
}
]
}
What I want is pull vote of a specific user from answer upvotes, and return the new update result.
For example, find a question with id 1, and get its specific answer with id 2, then from that answer pull my vote using userId inside upvotes.
I want to do it with a single findOneAndUpdate query
You can even use single $ positional with the $pull operator to update the nested array
db.collection.findOneAndUpdate(
{ "_id": ObjectId(1), "answers._id": ObjectId(2) },
{ "$pull": { "answers.$.upVotes": { "userId": ObjectId(4) }}}
)
I think I understood that you want to do a search in the specific array
db.collection.update(
{
"_id": "507f1f77bcf86cd799439011", // id field
"answers.upVotes._id":"507f1f77bcf86cd799439011" //id array
}
),{
"$set":{"answers.$.upVotes": {userId :"507f1f77bcf86cd799439011"}}},//edit
//use "addToSet" for add

MongoDB Regex $and $or Search Query

I am trying to construct a query that will accept multiple fields that can be searched over using regex for partial field matching that also has a hard constraint on other fields.
Example:
Collection: "Projects"
Required Information: { propertyId: "abc", clientId: "xyz" }
Fields to be Searched: name, serviceType.name, manager.name
Currently, I have a query like this, but if there are no results it returns all the results, which isn't helpful.
{
'$and': [
{ propertyId: '7sHGCHT4ns6z9j6BC' },
{ clientId: 'xyz' },
{ '$or':
[
{ name: /HVAC/gi },
{ 'serviceType.name': /HVAC/gi },
{ 'manager.name': /HVAC/gi }
]
}
]
}
If anyone has any insight into this it would be much appreciated.
Example Document:
{
_id: "abc",
propertyId: "7sHGCHT4ns6z9j6BC",
clientId: "xyz"
name: "16.000.001",
serviceType: {
_id: "asdf",
name: "HVAC"
},
manager: {
_id: "dfgh",
name: "Patrick Lewis",
}
}
The expected result is to only find documents where propertyId = 7sHGCHT4ns6z9j6BC AND one at least one of the following keys: name, serviceType.name, or manager.name match an inputted string, in this case, it's HVAC and if none of the regex fields match, then return nothing.
UPDATE
The issue was with MongoDB, after restarting it, everything worked.
Try following script:
db.collection.find({
$and:[
{propertyId:"7sHGCHT4ns6z9j6BC"},
{
$or:[
{name: /HVAC/i},
{"serviceType.name": /HVAC/i},
{"manager.name": /HVAC/i}
]
}]
})
Query above will return a document or documents if and only if propertyId matches and either of name, serviceType.name or manager.name matches desired regex.