Mongodb - remove or replace all array elements - mongodb

How can i replace all elements from a mongodb array element. As in below example, my requirement is to remove both object from skills array and add new elements in it.
{
"_id": "uniqueid",
"skills": [
{ "skill": "dancer" },
{ "skill": "singer" }
]
}
I need to replace all element of skills array field. How this can be achieved using mongodb java driver, or other query types?

You just need to use $set operator $set to set skills to a new value which will be an array of the new element you want to replace with.
db.collectionName.update(
{ _id: 'uniqueid' },
{ $set:
{
skills: [{'new elements'}]
}
}
)
if you want to remove all elements set the skills to an empty array {skills: []}
if you want to remove a certain elements based on a value use $pull operator $pull

Related

MongoDB, Cannot use the part (...) of (...) to traverse the element when trying $pull on nested array of documents

I am trying to $pull a certain document contained within a nested array, within another nested array.
The structure goes as follows:
*clubs{ "club_id",
"players"[{"player_id": 123,
"comments": [{"_id": "id"},
{"_id": "id2"}]
}]
}
I am trying to use the below in mongosh:
db.clubs.updateOne({"players.player_id": 363205}, {$pull: {"players.comments": {"players.comments._id": "5c61f001-768c-11ed-892f-346f24b28bd0"}}})
But when I submit this I get the following error:
MongoServerError: Cannot use the part (comments) of (players.comments) to traverse the element ({players: ...
Can someone please lend a hand here and let me know where I am going wrong? I've had a similar query work earlier, however it was only on 1 nested array of documents, rather than a nested array in a document that itself is contained in a nested array. Thanks in advance! :)
Update with $[<identifier>] filtered positional operator.
db.clubs.updateOne({
"players.player_id": 363205
},
{
$pull: {
"players.$[player].comments": {
"_id": "5c61f001-768c-11ed-892f-346f24b28bd0"
}
}
},
{
arrayFilters: [
{
"player.player_id": 363205
}
]
})
Demo # Mongo Playground

removing embedded documents by ObjectId

I am only able to remove (pull) embedded documents (here "items") one at a time.
In my example, "toRemove" is an array of ObjectIds (of cart.items).
db.collection('users').updateOne(
{ _id: new ObjectId(this._id) },
{$pull: {'cart.items': {'productId': toRemove}}}
)
This is not working.
But if I do toRemove[0], it will only remove the first document.
How can I remove them all at once ?
I think you need to use $pullAll instead of $pull to remove all matching instances from an array.
db.collection('users').updateOne(
{ _id: new ObjectId(this._id) },
{$pullAll: {'cart.items': {'productId': toRemove}}}
)
Read more about $pullAll here
I needed to use the special "$in" property, to delete all "items" whose "productId" is inside "toRemove" array :
return db.collection('users').updateOne(
{ _id: new ObjectId(this._id) },
{$pull: {'cart.items': {'productId': { "$in": toRemove }}}}
)

removing element of an array that with a match of certain element

I have a mongodb collection.
{ user_id: 1,
items : [ { _id: 1 }, { _id: 2}, {_id:3} ] }
I want to remove the items of the array having specific id. Can anybody explain what is wrong with the above query.
db.col.findOneAndUpdate({user_id:1},{$pull:{items:{$elemMatch:{_id:2}}}})
$pull takes an expression as a parameter so you don't have to use $elemMatch (doesn't work in this case). Try:
db.col.update({user_id:1},{$pull:{items:{_id:2}}})
So expression in this case means that MongoDB will remove the document having _id set to 2 but that document can have other properties as well.

Converting some fields in Mongo from String to Array

I have a collection of documents where a "tags" field was switched over from being a space separated list of tags to an array of individual tags. I want to update the previous space-separated fields to all be arrays like the new incoming data.
I'm also having problems with the $type selector because it is applying the type operation to individual array elements, which are strings. So filtering by type just returns everything.
How can I get every document that looks like the first example into the format for the second example?
{
"_id" : ObjectId("12345"),
"tags" : "red blue green white"
}
{
"_id" : ObjectId("54321"),
"tags" : [
"red",
"orange",
"black"
]
}
We can't use the $type operator to filter our documents here because the type of the elements in our array is "string" and as mentioned in the documentation:
When applied to arrays, $type matches any inner element that is of the specified BSON type. For example, when matching for $type : 'array', the document will match if the field has a nested array. It will not return results where the field itself is an array.
But fortunately MongoDB also provides the $exists operator which can be used here with a numeric array index.
Now how can we update those documents?
Well, from MongoDB version <= 3.2, the only option we have is mapReduce() but first let look at the other alternative in the upcoming release of MongoDB.
Starting from MongoDB 3.4, we can $project our documents and use the $split operator to split our string into an array of substrings.
Note that to split only those "tags" which are string, we need a logical $condition processing to split only the values that are string. The condition here is $eq which evaluate to true when the $type of the field is equal to "string". By the way $type here is new in 3.4.
Finally we can overwrite the old collection using the $out pipeline stage operator. But we need to explicitly specify the inclusion of other field in the $project stage.
db.collection.aggregate(
[
{ "$project": {
"tags": {
"$cond": [
{ "$eq": [
{ "$type": "$tags" },
"string"
]},
{ "$split": [ "$tags", " " ] },
"$tags"
]
}
}},
{ "$out": "collection" }
]
)
With mapReduce, we need to use the Array.prototype.split() to emit the array of substrings in our map function. We also need to filter our documents using the "query" option. From there we will need to iterate the "results" array and $set the new value for "tags" using bulk operations using the bulkWrite() method new in 3.2 or the now deprecated Bulk() if we are on 2.6 or 3.0 as shown here.
db.collection.mapReduce(
function() { emit(this._id, this.tags.split(" ")); },
function(key, value) {},
{
"out": { "inline": 1 },
"query": {
"tags.0": { "$exists": false },
"tags": { "$type": 2 }
}
}
)['results']

Select only documents with id value not in the collection

I have a collection ft with a number of records in it. However,i want to exclude certain ids that i have in a comma delimited list.
I am trying to do the following
var ids = [ "RQcWthREHBTfkybMy", "jiPrzQQWxbN5a8pEC", "5oFxC68WEggYzY7ah" ]
db.collection.find( { _id: { $ne: ids } } )
but i can only manage to exclude RQcWthREHBTfkybMy which is the first id in my list.
The $ne query operator behavior when the specified value is array is quite different from the the $eq operator. To check if a field value is not in the specified array you need to use the $nin query operator.
var ids = [ "RQcWthREHBTfkybMy", "jiPrzQQWxbN5a8pEC", "5oFxC68WEggYzY7‌​ah" ]
db.collection.find( { "_id": { "$nin": ids } } )