I have a nested array structured like this
{
"_id": "5dff75968102f11e20ae888e",
"docID": "Employees",
"data": [
[
"234768237",
"Value1",
],
[
"234768238",
"Value2"
],
[
"234768239",
"Value3"
]
]
}
Inside the nested data array, first element is employee ID, Ex: 234768237.
I would want to pass an array of employee ID's and delete the matching ones, for ex : [234768237, 234768238]
What i have tried so far
let employeeIDArray = [234768237, 234768238];
collection.updateOne(
{ docID: "Employees" },
{
$pull: {
"data.$[]": { "0": { $each: employeeIDArray } }
}
}
);
You're close, try:
let employeeIDArray = [234768237, 234768238];
collection.updateOne(
{ docID: "Employees" },
{
$pull: {
"data": { $in: employeeIDArray }
}
}
);
The $each modifier is only available for $push and $addToSet actions, read more about it here.
EDIT:
For Nested Array use $pullAll instead of $pull like so:
collection.updateOne(
{ docID: "Employees" },
{
$pullAll: {
"data.$[]": employeeIDArray
}
});
If you are using MongoDB's latest version then you can use below query to update using aggregation pipeline:
collection.updateOne(
{ docId: "Employees" },
[ {
$set: {
data: {
$filter: {
input: "$data",
cond: { $in: [ { $arrayElemAt: [ "$$this", 0 ] }, [ "234768237", "234768238" ] ] } }
}
}
} ],
{ upsert: true }
)
Related
I have the following mongo document:
{ Name: Peter,
Email: peter#mail.com,
EmailSuffix: peter#mail.com
}
I want to remove the substring before "#" of "EmailSuffix" field in all documents of the collection, so that the result will be:
{ Name: Peter,
Email: peter#mail.com,
EmailSuffix: #mail.com
}
I have tried the following:
db.collection.aggregate( [
{
$match: { EmailSuffix: { $regex: /.+?(?=#)/ } }
},
{
$addFields: {
EmailSuffix: { $split: [ "$EmailSuffix", "?" ] }
}
}
] ).forEach( doc => db.collection.updateMany( { _id: doc._id }, { $set: { EmailSuffix: doc.EmailSuffix[0] } } )`
But it doesn't run.
Use $indexOfCP to locate the first #. Then use $substrCP to do usual substring extraction.
db.collection.update({},
[
{
"$addFields": {
"EmailSuffix": {
"$substrCP": [
"$EmailSuffix",
{
"$indexOfCP": [
"$EmailSuffix",
"#"
]
},
{
"$strLenCP": "$EmailSuffix"
}
]
}
}
}
],
{
multi: true
})
Mongo Playground
I have following collection
[
{
"_id": ObjectId("57315ba4846dd82425ca2408"),
"myarray": [
{
"point": 5,
"userId": "570ca5e48dbe673802c2d035"
},
{
"point": 2,
"userId": "613ca5e48dbe673802c2d521"
},
{
"point": 4,
"userId": "570ca5e48dbe673802c2d045"
},
{
"point": 4,
"userId": "570ca5e48dbe473802c2d035"
}
]
}
]
I have a collection like above and I want to remove some objects inside array based on userID condition and after removing I have to update one field in mongo with size of array
I'm trying with the below query where removing array elements is working as excepted but array size is not updating properly
db.collection.update({
_id: ObjectId("57315ba4846dd82425ca2408")
},
{
$pull: {
"myarray": {
userId: {
$in: [
"570ca5e48dbe673802c2d035",
"613ca5e48dbe673802c2d521"
]
}
}
},
"$set": {
profilecount: {
$size: "$myarray"
}
}
})
to see result of query please click this link and run query https://mongoplayground.net/p/FtMk7ymacr3
One option is using an update with a pipeline:
db.collection.update({
_id: ObjectId("57315ba4846dd82425ca2408")
},
[{
$set: {
"myarray": {
$filter: {
input: "$myarray",
cond: {
$not: {
$in: [
"$$this.userId",
["570ca5e48dbe673802c2d035", "613ca5e48dbe673802c2d521"]
]
}
}
}
}
}
},
{$set: {profilecount: {$size: "$myarray"}}}
])
See how it works on the playground example
Image this data structure :
{
_id: 1
...
sections: [
{
Title: 'hello world',
Title2: '',
},
{
Title: 'goodbye',
Title2: ''
}
]
}
I need to update all Title2 from Title.
I tried things like :
db...update(
{ },
[{ $set:
{
"sections.Title2": "sections.Title",
}
}])
but without success. Also tried with updateMany and some variants like sections.$.Title2.
Thank you for any help
You can do via update + aggregation pipleine(mongod 4.2+) & $map as follow:
db.collection.update({
sections: {
$exists: true
}
},
[
{
$addFields: {
"sections": {
$map: {
input: "$sections",
as: "s",
in: {
"Title": "$$s.Title",
"Title2": "$$s.Title"
}
}
}
}
}
],
{
multi: true
})
Explained:
Find and replace the existing sections with mapped the necessary array values for Title2 to Title.
Add the option {multi:true} to update all documents in collection
playground
Improved version2:
db.collection.update({
sections: {
$exists: true
}
},
[
{
$addFields: {
"sections": {
$map: {
input: "$sections",
as: "s",
in: {
$mergeObjects: [
"$$s",
{
"Title2": "$$s.Title"
}
]
}
}
}
}
}
],
{
multi: true
})
Explained:
In this version you merge the changed value with the subdocument so you dont need to add every of the other fields that are nto going to be changed.
playground2
I have in my collection this structure:
{
_id: ObjectId('...'),
images: [
"images/key1",
"images/key2",
"images/key3",
"images/key4"
],
.... ,
....
}
So, I want to update all documents to:
{
_id: ObjectId('...'),
images: [
"key1",
"key2",
"key3",
"key4"
],
.... ,
....
}
Replacing in all values 'images/' with ''. Thanks 😁
you could done it with update aggregation like this
first match the doc and then in project use map and them split and choose last element
db.collection.update({},
[
{
$addFields: {
images: {
$map: {
input: "$images",
as: "i",
in: {
$last: {
$split: [
"$$i",
"images/"
]
}
}
}
}
}
}
],{multi:true})
https://mongoplayground.net/p/6fDBAlpKDBj
or use this
db.collection.update({},
[
{
$addFields: {
images: {
$map: {
input: "$images",
as: "i",
in: {
$arrayElemAt: [
{
$split: [
"$$i",
"images/"
]
},
1
]
}
}
}
}
}
],{multi:true})
replace $last with $arrayelementAt
https://mongoplayground.net/p/ecHMquZGazy
I was looking to pull some value from array and simultaneously trying to update it.
userSchema.statics.experience = function (id,xper,delet,callback) {
var update = {
$pull:{
'profile.experience' : delet
},
$push: {
'profile.experience': xper
}
};
this.findByIdAndUpdate(id,update,{ 'new': true},function(err,doc) {
if (err) {
callback(err);
} else if(doc){
callback(null,doc);
}
});
};
i was getting error like:
MongoError: exception: Cannot update 'profile.experience' and 'profile.experience' at the same time
I found this explanation:
The issue is that MongoDB doesn’t allow multiple operations on the
same property in the same update call. This means that the two
operations must happen in two individually atomic operations.
And you can read that posts:
Pull and addtoset at the same time with mongo
multiple mongo update operator in a single statement?
In case you need replace one array value to another, you can use arrayFilters for update.
(at least, present in mongo 4.2.1).
db.your_collection.update(
{ "_id": ObjectId("your_24_byte_length_id") },
{ "$set": { "profile.experience.$[elem]": "new_value" } },
{ "arrayFilters": [ { "elem": { "$eq": "old_value" } } ], "multi": true }
)
This will replace all "old_value" array elements with "new_value".
Starting from MongoDB 4.2
You can try to update the array using an aggregation pipeline.
this.updateOne(
{ _id: id },
[
{
$set: {
"profile.experience": {
$concatArrays: [
{
$filter: {
input: "$profile.experience",
cond: { $ne: ["$$this", delet] },
},
},
[xper],
],
},
},
},
]
);
Following, a mongoplayground doing the work:
https://mongoplayground.net/p/m1C1LnHc0Ge
OBS: With mongo regular update query it is not possible.
Since Mongo 4.2 findAndModify supports aggregation pipeline which will allow atomically moving elements between arrays within the same document. findAndModify also allows you to return the modified document (necessary to see which array elements were actually moved around).
The following includes examples of:
moving all elements from one array onto the end of a different array
"pop" one element of an array and "push" it to another array
To run the examples, you will need the following data:
db.test.insertMany( [
{
"_id": ObjectId("6d792d6a756963792d696441"),
"A": [ "8", "9" ],
"B": [ "7" ]
},
{
"_id": ObjectId("6d792d6a756963792d696442"),
"A": [ "1", "2", "3", "4" ],
"B": [ ]
}
]);
Example 1 - Empty array A by moving it into array B:
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696441") },
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, "$A" ] } } },
{ $set: { "A": [] } }
],
new: true
});
Resulting in:
{
"_id": {
"$oid": "6d792d6a756963792d696441"
},
"A": [],
"B": [
"7",
"8",
"9"
]
}
Example 2.a - Pop element from array A and push it onto array B
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"A": {$exists: true, $type: "array", $ne: [] }},
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, [ { $first: "$A" } ] ] } } },
{ $set: { "A": { $slice: ["$A", 1, {$max: [{$subtract: [{ $size: "$A"}, 1]}, 1]}] } }}
],
new: true
});
Resulting in:
{
"_id": {
"$oid": "6d792d6a756963792d696442"
},
"A": [
"2",
"3",
"4"
],
"B": [
"1"
]
}
Example 2.b - Pop element from array A and push it onto array B but in two steps with a temporary placeholder:
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"temp": { $exists: false } },
update: [
{ $set: { "temp": { $first: "$A" } } },
{ $set: { "A": { $slice: ["$A", 1, {$max: [{$subtract: [{ $size: "$A"}, 1]}, 1]}] } }}
],
new: true
});
// do what you need to do with "temp"
db.test.findAndModify({
query: { _id: ObjectId("6d792d6a756963792d696442"),
"temp": { $exists: true } },
update: [
{ $set: { "B": { $concatArrays: [ { $ifNull: [ "$B", [] ] }, [ "$temp" ] ] } } },
{ $unset: "temp" }
],
new: true
});