'MongoDB: Find the minimum element in array and delete it
I have a documents in MongoDB, one of them looks like this:
{
"_id" : 100,
"name" : "Something",
"items" : [
{
"item" : 47,
"color" : "red"
},
{
"item" : 44,
"color" : "green"
},
{
"item" : 39,
"color" : "blue"
}
]
}
In every document I need to find the minimum item and delete it. So it should be like this:
{
"_id" : 100,
"name" : "Something",
"items" : [
{
"item" : 47,
"color" : "red"
},
{
"item" : 44,
"color" : "green"
}
]
}
It looks like findAndModify
function should be used here but I can't go any further.
How to find the minimum element in array and delete it?
I'm using MongoDB and Pymongo driver.
Solution 1:[1]
If you are not restricted to having the query be in one single step, you could try:
step 1) use the aggregate function with the $unwind and $group operators to find the minimum item for each document
myresults = db.megas.aggregate( [ { "$unwind": "$items" },
{"$group": { '_id':'$_id' , 'minitem': {'$min': "$items.item" } } } ] )
step 2) the loop through the results and $pull the element from the array
for result in myresults['result']:
db.megas.update( { '_id': result['_id'] },
{ '$pull': { 'items': { 'item': result['minitem'] } } } )
Solution 2:[2]
Please find my solution written in plain javascript. It should work straight through MongoDb shell
cursor = db.students.aggregate(
[{ "$unwind": "$items" },
{ "$match": { "items.color": "green"}},
{ "$group": {'_id': '$_id', 'minitem': {
'$min': "$items.item"
}
}
}
]);
cursor.forEach(
function(coll) {
db.students.update({
'_id': coll._id
}, {
'$pull': {
'items': {
'item': coll.minitem
}
}
})
})
Solution 3:[3]
Starting in Mongo 4.4
, the $function
aggregation operator allows applying a custom javascript function to implement behaviour not supported by the MongoDB Query Language.
And coupled with improvements made to db.collection.update()
in Mongo 4.2
that can accept an aggregation pipeline, allowing the update of a field based on its own value,
We can manipulate and update an array in ways the language doesn't easily permit:
// {
// "name" : "Something",
// "items" : [
// { "item" : 47, "color" : "red" },
// { "item" : 39, "color" : "blue" },
// { "item" : 44, "color" : "green" }
// ]
// }
db.collection.update(
{},
[{ $set:
{ "items":
{ $function: {
body: function(items) {
var min = Math.min(...items.map(x => x.item));
return items.filter(x => x.item != min);
},
args: ["$items"],
lang: "js"
}}
}
}],
{ multi: true }
)
// {
// "name" : "Something",
// "items" : [
// { "item" : 47, "color" : "red" },
// { "item" : 44, "color" : "green" }
// ]
// }
$function
takes 3 parameters:
body
, which is the function to apply, whose parameter is the array to modify. The function here simply consists in first finding the minimumitem
from the array in order to thenfilter
it out.args
, which contains the fields from the record that thebody
function takes as parameter. In our case,"$items"
.lang
, which is the language in which thebody
function is written. Onlyjs
is currently available.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | megas |
Solution 2 | juanreyesv |
Solution 3 |