Mongoose update document with $or condition - node.js

I would like to search for all activity which has the same action_object.reply.id or action_target.reply.id. Something like this:
Activity
.find({ $or: [
{ 'action_object.reply.id': replyId },
{ 'action_target.reply.id': replyId }
]});
But i also only want to update the removed attribute like this:
Activity
.update({ 'action_object.reply.id': replyId }, {
'action_object.reply.removed': true }, { multi: true });
Activity
.update({ 'action_target.reply.id': replyId }, {
'action_target.reply.removed': true }, { multi: true });
Is it possible to somehow combine these two queries? I want to update action_target.reply.removed where action_target.reply.id or action_object.reply.removed where action_object.reply.id.
Or i must write two different queries for this like i did above.

The first argument to the update call is the query object, so you can simply use the same $or query. Mongo will update all documents retrieve by the query.
Activity
.update({ $or: [
{ 'action_object.reply.id': replyId },
{ 'action_target.reply.id': replyId }
]}, {'action_object.reply.removed': true }, { multi: true });

With 4.2, you can use $cond
// Configuration
[
{
"action_object": {
"reply": {
"id": "bar",
"removed": false
}
}
},
{
"action_target": {
"reply": {
"id": "foo",
"removed": false
}
}
}
]
// Query
db.collection.update({
$or: [
{
"action_object.reply.id": "foo"
},
{
"action_target.reply.id": "foo"
}
]
},
[
{
$set: {
"action_object.reply.removed": {
$cond: [
{
$eq: [
"foo",
"$action_object.reply.id"
]
},
true,
"$$REMOVE"
]
},
"action_target.reply.removed": {
$cond: [
{
$eq: [
"foo",
"$action_target.reply.id"
]
},
true,
"$$REMOVE"
]
}
}
}
],
{
multi: true
})
https://mongoplayground.net/p/tOLh5YKRVX1

Related

How do i only get matching object from nested array in mongodb using find or aggregate?

My model
having this field :
canReview: [
{
status: {
type: Boolean
,
}
]
Records are :
[
{
_id: 1,
name: "aaaa",
canReview: [
{
status: true
},
{
status: false
},
{
status: false
}
]
},
{
_id: 2,
name: "abbb",
canReview: [
{
status: false
},
{
status: false
},
{
status: false
}
]
}
]
I want the result like only status true records from nested array too
I query like :
{canReview.status : true}
result :
[
{
"_id": 1,
"name": "aaaa",
"canReview": [
{
"status": true
}
],
}
]
nested array contains only records those status is true...
Need more details explanation.
Use $anyElementTrue
db.collection.find({
$expr: {
"$anyElementTrue": "$canReview.status"
}
})
Mongo Playground

updateOne based on condition

await products.updateOne(
{
$and: [
{ name: { $eq: name } },
{ $expr: { $lt: ["$remaining", "$capacity"] } },
],
},
{ $inc: { remaining: 1 } },
{ returnOriginal: false }
);
Instead of having the condition in the query like so { $expr: { $lt: ["$remaining", "$capacity"] } }, is there a way to include this condition in the update argument?
The reason for this is so that I want the returned matchCount to return 1 if the name is matched.
Yes, you can do that if you use mongo 4.2+ using aggregate update.
db.collection.update({
$and: [ //condition goes here
{
name: {
$eq: "name"
}
},
],
},
[
{
"$set": { //conditional update
"remaining": {
"$switch": {
"branches": [
{
case: {
$lt: [ //condition to update
"$remaining",
"$capacity"
]
},
then: {
$add: [ //true case
"$remaining",
1
]
}
}
],
default: {
$add: [ //if no match
"$remaining",
0
]
}
}
}
}
}
])
playground

update mongodb field by an array object property

i am trying to carry a simple update query operation with MongoDB from my node js application that will run every night using node-cron but i haven't been able to get the update operation to work
.documents in my db look like
[
{
Balance: 4000,
name: "Steph curry",
password: "*****",
created_At: ISODate("2022-04-19T07:17:29.243Z"),
deposits: [
{
amount: 1000,
paid: false,
expiry: 28903708478, // this should be a timestamp
credit: 150
},
{
amount: 1000,
paid: false,
credit: 100,
expiry: 28903708478 // this should be a timestamp
}
]
}
]
i want to query for all users where their deposit has expired (that is Date.now() > expiry )
and their paid value is false and then add the credit to their balance value, then turn the paid value to true.
/ basically what i want is something like this
db.collection.update({
"deposits.paid": false,
"deposits.expiry": { $lt: "$$NOW" }
},
{
ballance: {
$add: [ "deposits.$.credit", "$balance" ]
},
"deposits.$.paid": true
})
I don't think your expiry is a valid timestamp (28903708478=2885/12/2 Sunday 15:54:38), so convert it yourself.
$map
$add
$cond
$mergeObjects
db.collection.update({
"deposits.paid": false,
"deposits.expiry": { $lt: 28903708479 }
},
[
{
$set: {
Balance: {
$add: [
"$Balance",
{
$sum: {
$map: {
input: "$deposits",
as: "d",
in: {
$cond: {
if: {
$and: [
{ $not: "$$d.paid" },
{ $lt: [ "$d.expiry", 28903708479 ] }
]
},
then: "$$d.credit",
else: 0
}
}
}
}
}
]
}
}
},
{
$set: {
deposits: {
$map: {
input: "$deposits",
as: "d",
in: {
$mergeObjects: [
"$$d",
{
paid: {
$cond: {
if: {
$and: [
{ $not: "$$d.paid" },
{ $lt: [ "$d.expiry", 28903708479 ] }
]
},
then: true,
else: false
}
}
}
]
}
}
}
}
}
],
{
multi: true
})
mongoplayground

How to select either a field, if it exists or 0 inside $add operation?

I am using the $add operator in mongoose aggregate to sum a bunch of fields.
{ $set: { newField: { $add: ["$fieldOne", "$fieldTwo", "$fieldThree"] } } },
One of those fields fieldThree only exists in some documents. So in the documents in which it doesn't exists, I would like to replace it with 0. How may I do so?
db.collection.update({},
[
{
$addFields: {
fieldThree: {
$ifNull: [
"$fieldThree",
0
]
}
}
},
{
$set: {
newField: {
$add: [
"$fieldOne",
"$fieldTwo",
"$fieldThree"
]
}
}
},
],
{
multi: true
})
https://mongoplayground.net/p/L422i6DPE8k

MongoDB: query multiple $elemmatch with $all

In my app, I have a polls collection and the a document looks like this;
/* POLLS */
{
...
"type": "COMMON",
"__v": {
"$numberInt": "0"
},
"targets": [
{
"code": "city",
"logic": "eq",
"value": "4"
},
{
"code": "city",
"logic": "eq",
"value": "15"
}
]
}
And the targeting key is an array contains of objects of targets.
Each target's code can be city or gender.
So it means, "gender" may not be found in a Poll document.
Depending on that when fetching Polls, I want the ones matching with my User's fields, if the code exists.
For example; When fetching the Polls from a User's feed, If a Poll contains gender targeting, I want to find polls matching with my User's gender.
My code is like this:
Poll.find({
state: "PUBLISHED",
approval: "APPROVED",
$or: [
{
targets: {
$exists: true,
$eq: []
}
},
{
targets: {
$exists: true,
$ne: [],
$all: [
{
$elemMatch: {
code: {
$exists: true,
$eq: "city"
},
value: {
$eq: foundUser.cityCode // equals to 4 in this example
}
}
},
{
$elemMatch: {
code: {
$exists: true,
$eq: "gender"
},
value: {
$eq: foundUser.gender // equals to m in this example
}
}
}
]
}
}
]
})
However, the list returns empty for the Poll document I wrote above.
When the part below commented out, the code returns the correct polls.
Poll.find({
state: "PUBLISHED",
approval: "APPROVED",
$or: [
{
targets: {
$exists: true,
$eq: []
}
},
{
targets: {
$exists: true,
$ne: [],
$all: [
{
$elemMatch: {
code: {
$exists: true,
$eq: "city"
},
value: {
$eq: foundUser.cityCode // equals to 4 in this example
}
}
},
// {
// $elemMatch: {
// code: {
// $exists: true,
// $eq: "gender"
// },
// value: {
// $eq: foundUser.gender // equals to m in this example
// }
// }
// }
]
}
}
]
})
May anyone help me with the situation that return the right polls when gender or country targeted?
Thanks, Onur.
Return targets field is an array whose elements match the $elemMatch criteria in array
Try that query
Poll.find({
state: "PUBLISHED",
approval: "APPROVED",
$or: [
{
targets: {
$exists: true,
$eq: []
}
},
{
targets: {
$exists: true,
$ne: [],
$all: [
{
$elemMatch: {
code: {
$exists: true,
$eq: "city"
},
value: {
$eq: "4" // equals to 4 in this example
}
}
}
]
}
},
{
targets: {
$exists: true,
$ne: [],
$all: [
{
$elemMatch: {
code: {
$exists: true,
$eq: "gender"
},
value: {
$eq: 'm' // equals to m in this example
}
}
}
]
}
}
]
})

Resources