13

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.

1
  • 21
    haha, you doing the 10gen course? week3-2 ? Commented Jul 7, 2013 at 3:23

3 Answers 3

18

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'] } } } )
Sign up to request clarification or add additional context in comments.

4 Comments

If you want filter like where minimum of red, or green item, you can add {'$match': {"items.color": "red"} } in your aggregate syntax.
I added following code by mongo shell for(i=0; i<result.length; i++) { db.students.update({ '_id': result[i]['_id']}, { '$pull': { 'items': { 'item': result[i]['minitem'] } } } ) }
Im able to runt he first query.. Im not able to perform update operation.. Im using for(i=0;i<result.length;i++)
I had to remove the ['result'] to make it work. The code is like this: for result in myresults: db.megas.update( { '_id': result['_id'] }, { '$pull': { 'items': { 'item': result['minitem'] } } } )
9

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
            }
        }
    })
})

3 Comments

the match statement is optional. But useful to further narrow down a selection from array
Just to add to the above answers, you could also look into the for... of of Javascript: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
above will fetch at a time 20 records what to do to get all records and update them?
0

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 minimum item from the array in order to then filter it out.
  • args, which contains the fields from the record that the body function takes as parameter. In our case, "$items".
  • lang, which is the language in which the body function is written. Only js is currently available.

1 Comment

Great, great feature actually!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.