50

I'm trying to update some field in my collection depending on a condition.

I want to set field active to true if the condition is true and to false otherwise

This is update without condition

db.consent.update(
{}, //match all
{
    $set: {
        "active": true
    }
}, 
{
    multi: true,
}

)

I would like to add a condition to update like this:

db.consent.update(
{},
$cond: {
    if: {

        $eq: ["_id", ObjectId("5714ce0a4514ef3ef68677fd")]

    },
    then: {
        $set: {
            "active": true
        }
    },
    else: {
        $set: {
            "active": false
        }
    }
}, 
{
    multi: true,
}

)

According to https://docs.mongodb.org/manual/reference/operator/update-field/ there is no $cond operator for update.

What are my options here to execute this update as a single command?

Community
  • 1
  • 1
q99
  • 961
  • 2
  • 13
  • 27
  • Possible duplicate of [MongoDB, conditional upserts or updates](http://stackoverflow.com/questions/5540103/mongodb-conditional-upserts-or-updates) – BanksySan Apr 18 '16 at 16:10

6 Answers6

72

Starting Mongo 4.2, db.collection.update() can accept an aggregation pipeline, finally allowing the update/creation of a field based on another field:

// { a: "Hello", b: "World" }
// { a: "Olleh", b: "Dlrow" }
db.collection.updateMany(
  {},
  [ { $set: { active: { $eq: [ "$a", "Hello" ] } } } ]
)
// { a: "Hello", b: "World", active: true  }
// { a: "Olleh", b: "Dlrow", active: false }
  • The first part {} is the match query, filtering which documents to update (in our case all documents).

  • The second part [ { $set: { active: { $eq: [ "$a", "Hello" ] } } } ] is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline). $set is a new aggregation operator and an alias of $addFields. Then any aggregation operator can be used within the $set stage; in our case a conditional equality check on which depends the value to use for the new active field.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
32

We can do it using aggregation pipeline. Here i am updating male to female and female to male.

db.customer.updateMany(
   { },
   [
     { $set: { gender: { $switch: {
                           branches: [
                               { case: { $eq: [ "$gender", 'male' ] }, then: "female" },
                               { case: { $eq: [ "$gender", 'female' ] }, then: "male" }
                           ],
                           default: ""
     } } } }
   ]
)
Neeraj Negi
  • 704
  • 8
  • 5
14

You can't.

Mongo doesn't support combining fields, conditionals etc. in the update statement.


See https://stackoverflow.com/a/56551655/442351 below.

BanksySan
  • 27,362
  • 33
  • 117
  • 216
13

You can update MongoDB document conditionally using findAndModify() or findOneAndUpdate() if you have MongoDB version 3.2+

Saleem
  • 8,728
  • 2
  • 20
  • 34
  • 4
    From the documentation `The findAndModify command modifies and returns a single document` . So this would be good for one document only, but I need to update the entire collection. So I think I'm basically stuck with: 1) Two phase commit 2) 2 queries 3) Some other document, that would hold info about this one 4) Change the implementation – q99 Apr 19 '16 at 08:15
9

Of course you can.... by running 2 queries

db.collection.update({condition}, { $set: { state } }, { multi: true });
db.collection.update({!condition}, { $set: { state } }, { multi: false });

for your example case

db.consent.update(
  {"_id": ObjectId("5714ce0a4514ef3ef68677fd")},
  { $set: { "active": true } });

db.consent.update(
  {"_id": {$ne: ObjectId("5714ce0a4514ef3ef68677fd")}},
  { $set: { "active": false } },
  { multi: true });
  • 2
    Here the `multi` option is for applying the modifier on multiple matching records and not as `$set` value. If you only want to update the first matching record, set `multi` to `false` (default), otherwise, explicitly mention `multi` as `true` to update all records. – pranavcode Oct 08 '19 at 23:11
5
db.consent.update(
    {
       //YOUR CONDITIONAL HERE TO APLLAY UPDATE ONLY IF CONDITIONAL HAPPEN, SO THE "active": true WILL BE APPLY. 
    }, 
    {
       $set: {
         "active": true,
         "active2": FALSE,
       }
    }, 
    {
        multi: true,
    }
)