How to match field value based on condition using MongoDB? - 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") }
]
})

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

Store expression/condition in document

I'm new to mongodb and am unable to figure out if the below is even possible.
Can I store a condition, such as gt, lt, etc., inside a field in a document and then utilize it in a query?
So, given the following documents:
{
title : "testTitle1",
score : 55,
condition : "gt"
}
{
title : "testTitle2",
score : 30,
condition : "lt"
}
And given an inputScore = 75, only testTitle1 document would be returned because 75 is greater than ("gt") 55. The second document would not be returned because it is not less than ("lt") 30.
Any ideas?
Thanks
Yes, you can the params passed to the query is simply an object. You will need to use the mongodb operators unless you want to add additional processing before you send the query.
As an example:
const data = {
title : "testTitle1",
score : 55,
condition : "$gt"
};
const query = {
score: {}
};
query.score[data.condition] = data.score;
console.log(query);
Example with additional operator conversion:
const data = {
title : "testTitle1",
score : 55,
condition : "gt"
};
const query = {
score: {}
};
switch (data.condition) {
case "gt":
query.score["$gt"] = data.score;
break;
case "lt":
query.score["$lt"] = data.score;
break;
}
console.log(query);
if you want pure mongodb query, you can use $expr operator in your query or aggregation.
db.collection.find({
$expr: {
$or: [
{
$and: [
{$eq: ['$condition', 'gt']},
{$gt: [75, '$score']}
]
},
{
$and: [
{$eq: ['$condition', 'lt']},
{$lt: [75, '$score']}
]
}
]
}
})
i hope you get the idea
The query is with aggregation framework. I use the $switch for checking if the conditionhas a gt or lt value and return a trueor false after the inputScore is compared with the score. This compared result matches gives the filter condition to include or reject the input document.
var inputScore = 75;
db.gtlt.aggregate( [
{ $addFields: {
matches: {
$switch: {
branches: [
{
case: { $eq : [ "$condition", "gt" ] },
then: { $cond: [ { $gt: [ inputScore, "$score" ] }, true, false ] }
},
{
case: { $eq : [ "$condition", "lt" ] },
then: { $cond: [ { $lt: [ inputScore, "$score" ] }, true, false ] }
},
],
default: false
}
}
} },
{ $match: { matches: true } },
{ $project: { matches: 0 } }
] )

mongodb $or always return false (const)

I make an aggregation pipeline to retrive documents and add a new field "expired" (boolean), its value is based on the field "expireAt" (Date)
the expired field considerd true if:
expiredAt is missing or null or empty
expiredAt < now
this is my trial:
{project:
expired: {
$not: {
$or: [{ expireAt: null }, { $gte: ['$expireAt', new Date()] }]
}
}
}
this code always give me false even if the document has an expireAt value whitch is < now
by performing explain:
{ '$project': { _id: true, expireAt: true, expired: { '$cons
t': false } } }
query result:
note the expireAt field and the corresponding expired value
today is: 27/11/2018
{ expired: false },
{ expireAt: 2019-07-15T17:18:11.000Z, expired: false },
{ expireAt: 2017-07-16T17:18:11.000Z, expired: false },
also {expireAt:{$exists:false}} give error:
MongoError: Unrecognized expression '$exists'at queryCallback
any idea to check the existence of the field (weather its value is null or not)
Use $cond operator to achieve
Below query help you :
I have used date in my field.
db.getCollection('chat').aggregate([
{
$project: {
'date': 1,
"expired": {
$cond: {
if: { $gte: ['$date', new Date()] },
then: false,
else: true
}
}
}
}
])
With $or
db.getCollection('chat').aggregate(
[
{
$project:
{
date: 1,
expired: { $or: [ { $lt: [ "$date", new Date() ] }, { $eq: [ "$date", null ] } ] }
}
}
]
)
the following code worked with me:
expired:{
$and: ['$expireAt', { $lt: ['$expireAt', new Date()] }]
}

MongoDB update with condition

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