MongoDB UpdateMany - mongodb

I need to update various fields in mongo creating a new field. Example:
db.paymentTransaction.updateOne(
{status: "PARTIALLY_REFUNDED"},
{amount: EXISTS}
{
$set: {
"amountRefundRemaining": {
FIELD_B - FIELD_A
}
}
}
)
I need to create the field amountRefundRemaining. But I need to fill this new field with the result of the substraction of Field_B minus Field_A. But I only need to do this where status=PARTIALLY_REFUNDED and amount exists
Im using mongoDB 4.4.
Any ideias?

Query
if status=PARTIALLY_REFUNDED and amount exists
add field amountRefundRemaining with value FIELD_B - FIELD_A
*pipeline update requires MongoDB >= 4.2
PlayMongo
update(
{"$and":
[{"status": {"$eq": "PARTIALLY_REFUNDED"}}, {"amount": {"$exists": true}}]},
[{"$set":
{"amountRefundRemaining": {"$subtract": ["$FIELD_B", "$FIELD_A"]}}}],
{"multi": true})

Related

Complex Conditional mongodb query to match value if exists

I'm trying a condition if it's possible or not needed some answers if it's can be done.
Let's say I have a collection named : Resturant
Resturant
id
name
food
so and i have 4 rows :
1 , resturant1, burger
2 , resturant2, sandwich
3 , resturant2, burger
4 , resturant3, burger
So what i'm trying to achieve here is from a single query to fetch resturant1 & resturan2 values like
{"$match": {"$expr": {"$in": ["resturant1", "resturant2"]}
but if the food already exists in resturant1 then don't fetch that value from resturant2 so if burger already exists in resturant1 then do not fetch it from resturant2. so the result will be only 2 rows :
1 , resturant1, burger
2 , resturant2, sandwich
We can achieve this after fetching the result and overriding the already exists values but i was seeing if we can use any condition in mongodb query itself.
One option is using $setWindowFields (since mongodb version 5.0):
$match the relevant documents by name
Use $setWindowFields to temporarily add a set of all food types up to this document
$match only documents with food that is not in the document food.
Remove the added field
db.collection.aggregate([
{$match: {name: {$in: ["resturant1", "resturant2"]}}},
{$setWindowFields: {
sortBy: {name: 1},
output: {foodSet: {$addToSet: "$food", window: {documents: ["unbounded", -1]}}}
}},
{$match: {$expr: {$not: {$in: ["$food", "$foodSet"]}}}},
{$unset: "foodSet"}
])
See how it works on the playground example

Specific Field Wont Display In Mongo DB Aggregation Pipeline

I have a collection of Book Reviews where I am trying to find users who have created multiple reviews (lets say 5), I also want to return the number of reviews, their unique ID and their Name.
So far I have managed to find a way of doing this through aggregation, however for the life of me I cant seem to return the name field, I assumed a simple $project would be fine but instead I can only see the ID and the Number of reviews someone has made, what am i missing to fix this?
Current Code:
db.bookreviews.aggregate([
{"$group": {"_id": "$reviewerID","NumberOfReviews": { "$sum": 1 }}},
{"$match": {NumberOfReviews: {"$gte": 5}}},
{"$project":{_id:1,NumberOfReviews:1, reviewerName:1}},
])
Returned Values:
{IDXYZ, NumberofReviews 5},
{IDABC, NumberofReviews 5},
{ID123, NumberofReviews 5}
you can use $first to keep the first document of that group and keep the value of reviewerName in your $group stage and you can remove the $project.
db.bookreviews.aggregate([
{"$group": {"_id": "$reviewerID","NumberOfReviews": { "$sum": 1 }, "reviewerName": { "$first": "$reviewerName" } } },
{"$match": {"NumberOfReviews": {"$gte": 5}}},
])

How can i search by _id's feature in mongodb

For example, I want to update half of data whose _id is an odd number. such as:
db.col.updateMany({"$where": "this._id is an odd number"})
Instead of integer, _id is mongo's ObejectId which be regard as hexadecimal "string". It is not supported to code as:
db.col.updateMany(
{"$where": "this._id % 2 = 1"},
{"$set": {"a": 1}}
)
so, what is the correct format?
And what if molding according to _id?
This operation can also be done using two database calls.
Get List of _id from collection.
Push only ODD _id into an array.
Update the collection.
Updating the collection:
db.collection.update(
{ _id: { $in: ['id1', 'id2', 'id3'] } }, // Array with odd _id
{ $set: { urkey : urValue } }
)

filter subdocuments where field does not exist

I have collection of objects where each object contains versions some of which have delete field and would like to filter these which were not deleted or later than the given timestamp.
db
.getCollection('test')
.aggregate([
{$project:
{versions:
{$filter:
{input: '$versions',
as: 'version',
cond:
{
$or: [
{$gte: ['$$version.delete', 3]},
{'$$version.delete': {$exists: false}}
]
}
}
}
}
}
])
but field name probably can't be used inside filter because I get an error: invalid operator '$$version.delete'
Any ideas what is the proper syntax of this query?
You want to use aggregation syntax for checking type of delete field and comparing it to missing which is what $exists:false would be:
{$eq:[{$type:'$$version.delete'},"missing"]}

How can I aggregate the documents in an array instead of in a collection in MongoDB?

I have the following collection cidade on my MongoDB database:
{
"_id" : 0,
"nome" : "CIDADE0",
"qtdhab" : 1231043
}
So, here's what I want to do. I'm trying to do the equivalent of this SQL query in MongoDB:
SELECT MAX(QTDHAB) FROM CIDADE WHERE QTDHAB <= (SELECT AVG(QTDHAB) FROM CIDADE);
Basically, I want the biggest value of the field qtdhab from the collection cidade which follows the condition of being lower than the average value of the same field qtdhab on the same collection cidade. So, I have mapped this into 3 queries, like this:
var resultado = db.cidade.aggregate({"$group": {"_id": null, "avgHab": {"$avg": "$qtdhab"}}}).toArray()
var resultado2 = db.cidade.find({qtdhab: {$lte: resultado[0].avgHab}}).toArray()
resultado2.aggregate({"$group": {"_id": null, "maxHab": {"$max": "$qtdhab"}}})
The problem is, as I found out the hard way, that there is no .aggregate method for an array such as resultado2, so the last query returns an error. Is there any other way for me to get the biggest value for the field qtdhab out of this array of documents that was generated by these 2 queries?
You can achieve this by using only one query(aggregation):
db.cidade.aggregate([
/*find the avg and keep also the aggregated field*/
{"$group": {
"_id": null,
"qtdhab" : {"$push" :"$qtdhab"},
"avgHab": {"$avg": "$qtdhab"}
}},
/*unwind the array*/
{$unwind: "$qtdhab"},
/*get the max from the fields less than the avg*/
{"$group": {
"_id": null,
"res" : {"$max" : {$cond :[{$lte :["$qtdhab", "$avgHab"]}, "$qtdhab", null]} },
}}
])