MongoDB update with condition - mongodb

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?

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.

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: ""
} } } }
]
)

You can't.
Mongo doesn't support combining fields, conditionals etc. in the update statement.
See https://stackoverflow.com/a/56551655/442351 below.

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

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

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

Related

How to add new field conditionally in MongoDB?

I have an aggregation pipeline in which i want to add new field based on certain condition. My pipeline is like this
[
{ // match stage
$or:[
{
$and: [
{placement: {'$nin': [-1,-2]}},
{contract_proposal_metadata : {$exists: true}}
]
},
{
risk_info_request_metadata: {$exists: true}
}
]
}
]
Now i want to add a new field record_type based on the condition that if contract_proposal_metadata exists so record type will be 'renewal' and if risk_info_request_metadata is exists then record_type will be request.
How can i achieve this?
You are not adding new field conditionally. You are always adding the field, just with different values.
There is $cond operator which returns 1 of 2 values depending on condition in the first argument.
You already know $exist for the $match stage, and the equivalent operator to use in aggregation expression is $type
[
{ // match stage
.....
},
{ // adding the field
$addFields: {
record_type: { $cond: {
if: { $eq: [ { $type: "$contract_proposal_metadata" }, "missing" ] },
then: "request",
else: "renewal"
} }
}
}
]
You need to use aggregate update
db.collection.update({
placement: { //Your match goes here
"$nin": [
-1,
-2
]
},
},
[
{
$set: {
status: {
$switch: {
branches: [
{ //update condition goes here
case: {
$ifNull: [
"$contract_proposal_metadata",
false
]
},
then: "renewal"
},
{
case: {
$ifNull: [
"$risk_info_request_metadata",
false
]
},
then: "request"
},
],
default: ""
}
}
}
}
],
{
multi: true
})
It supported from mongo 4.2+
$exists cannot be used, hence $ifnull used
playground

Using $exists in MongoDB $cond

For background, I have to create a field in a collection, but ONLY if another known field (an array) is not empty. I'm trying to make a boolean filter with the $and and some conditions:
$set: {
clientsAllowed: {
$cond: {
if: {
$and: [
{
businessAllowed: { $exists: true },
},
{
businessAllowed: { $type: "array" },
},
{
businessAllowed: { $ne: [] },
},
],
},
then: [...],
else: [...],
},
}
}
But I get this error:
Invalid $set :: caused by :: Unrecognized expression '$exists'
Is the $exists wrongly formatted? Or is the $and stage? Any ideas?
Type cond for businessAllowed is enough. You don't need to check exists or not.
db.collection.aggregate([
{
$set: {
clientsAllowed: {
$cond: {
if: {
$and: [
{
"$eq": [
{
$type: "$businessAllowed"
},
"array"
]
},
{
$ne: [
"$businessAllowed",
[]
]
}
]
},
then: [],
else: []
}
}
}
}
])
mongoplayground

MongoDb: Select a random record with a specifi condition and update it

Friends
I have a collection with around 20 records of lastAccessed as null and now I want to select a random lastAccessed and update it with $$Now for which I have the below code
db.myCollection.aggregate([
{ $match: { lastAccessed: { $exists: False} }},
{ $sample:{ size: 1 }}
]);
db.myCollection.updateOne(
{ _id: 1 },
{
$set: {
tableName: 'myTable',
lastAccessed: '$$NOW'
}
})
My question is how do I know the id of the randomly selected record to update it correctly ?
For your scenario, you can use $merge at the end of the aggregation pipeline to perform update by id behaviour.
db.collection.aggregate([
{
$match: {
"lastAccessed": {
$exists: false
}
}
},
{
"$sample": {
"size": 1
}
},
{
$set: {
tableName: "myTable",
lastAccessed: "$$NOW"
}
},
{
"$merge": {
"into": "collection",
"on": "_id",
"whenMatched": "replace"
}
}
]).forEach( function(myDoc) { print( "tableName: " + myDoc.tableName ); } );
Here is the Mongo playground for your reference.
If we don't want to use aggregate,
To get Updated Document, can use findOneAndUpdate()
db.collection.findOneAndUpdate(
{ lastAccessed: { $exists: false } },
{ $set: { lastAccessed: "$$NOW" } },
{ returnOriginal: false }
)
Use { returnOriginal: true | false } option for Mongodb 3.6 earlier version,
For MongoDb 3.6 and after 3.6 Version, can use { returnDocument: "after", "before" },
{ new: true | false } option for mongoose

MongoDB, is there a statement similar to if then elif in sql?

Query is to find people whose age is shown and if their grade is 5 or higher then they will get honours, othewise fail. Can I use $cond with find?
db.test.find({age:{$exists:true}},{$cond: {if: "grade":5, then:"Honours" : true, else: "Honours" : "fail"}})
I also tried
db.test.find({$and: [{age:{$exists:true}}, {grade: {$gte:"5"}}]}, {$set:{"Honours":"true"}}, {multi:true})
But neither come close. Any help/direction is very much appreciated.
Check this.
db.test.aggregate([
{
$match: {
"age": {
"$exists": true
}
}
},
{
$project: {
"Honours": {
$switch: {
branches: [
{
case: {
"$gte": [
"$grade",
5
]
},
then: "true"
}
],
default: "fail"
}
}
}
}
])
.find projection only allows include / exclude fields, neither transform them nor add new field. Use MongoDB aggregation
db.test.aggregate([
{
$match: {
age: {
$exists: true
}
}
},
{
$project: {
Honours: {
$cond: [
{
$gte: [
"$grade",
5
]
},
true,
"fail"
]
}
}
}
])
MongoPlayground

How to match field value based on condition using MongoDB?

I have tried for match same value based on if else condition using MongoDB but value is not match.
var abc = false;
db.getCollection('deviceHistory').find({
$match: {
$cond: {
if: {
$eq: [abc, false ]
},
then: {
'purchaserId':ObjectId("5d47bd2f005d3e192c3e82de")
},
else:{
'sellerId':ObjectId("5d47bd2f005d3e192c3e82de")
}
}
}
})
You can use the $or operator:
db.getCollection('deviceHistory').find({
$or : [
{ abc: false, purchaserId: ObjectId("5d47bd2f005d3e192c3e82de") },
{ abc: true, sellerId: ObjectId("5d47bd2f005d3e192c3e82de") }
]
})