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
Related
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
I am trying to find the latest "order" in "orders" array in the whole collection (Not only in the one object).
Data:
[
{
_id: 1,
orders: [
{
title: 'Burger',
date: {
$date: '2021-07-18T13:12:08.717Z',
},
},
],
},
{
_id: 2,
orders: [
{
title: 'Salad',
date: {
$date: '2021-07-18T13:35:01.586Z',
},
},
],
},
];
Code:
var restaurant = await Restaurant.findOne({
'orders.date': 1,
});
Rather simple:
db.collection.aggregate([
{ $project: { latest_order: { $max: "$orders.date" } } }
])
If you like to get the full order use this:
db.collection.aggregate([
{
$project: {
latest_order: {
$first: {
$filter: {
input: "$orders",
cond: { $eq: [ "$$this.date", { $max: "$orders.date" } ] }
}
}
}
}
},
{ $sort: { "latest_order.date": 1 } },
{ $limit: 1 }
])
Mongo Playground
You have to use aggregation for that
db.collection.aggregate([
{ $unwind: "$orders" },
{ $sort: { "orders.date": -1 } },
{ $limit: 1 },
{
"$group": {
"_id": "$_id",
"orders": { "$first": "$orders" }
}
}
])
Working Mongo playground
hello I have this function where I want to calculate the number of orders for each status in one array, the code is
let statusEnum = ["pending", "canceled", "completed"];
let userOrders = await Orders.aggregate([
{
$match: {
$or: [
{ senderId: new mongoose.Types.ObjectId(req.user._id) },
{ driverId: new mongoose.Types.ObjectId(req.user._id) },
{ reciverId: new mongoose.Types.ObjectId(req.user._id) },
],
},
},
{
$group: {
_id: null,
totalOrders: { $sum: 1 },
totalPendingOrders: "??", //I want to determine this for each order status
totalCompletedOrders: "??",
totalCanceledOrders: "??",
},
},
]);
so I could add add a $match and use {status : "pending"} but this will filter only the pending orders, I could also map the status enum and replace each element instead of the "pending" above and then push each iteration in another array , but that just seems so messy, is there any other way to calculate total for each order status with using only one aggregate?
thanks
You can use group as you used, but with condition
db.collection.aggregate([
{
$group: {
_id: null,
totalPendingOrders: {
$sum: { $cond: [ { $eq: [ "$status", "pending" ] }, 1, 0 ] }
},
totalCompletedOrders: {
$sum: { $cond: [ { $eq: [ "$status", "completed" ] }, 1, 0 ] }
},
totalCanceledOrders: {
$sum: { $cond: [ { $eq: [ "$status", "canceled" ] }, 1, 0 ] }
}
}
}
])
Working Mongo playground
I am trying to wrap my head around the query which I am trying to make with mongoose on Node JS. Here is my dataset:
{"_id":{"$oid":"5e49c389e3c23a1da881c1c9"},"name":"New York","good_incidents":{"$numberInt":"50"},"salary":{"$numberInt":"50000"},"bad_incidents":"30"}
{"_id":{"$oid":"5e49c3bbe3c23a1da881c1ca"},"name":"Cairo","bad_incidents":{"$numberInt":"59"},"salary":{"$numberInt":"15000"}}
{"_id":{"$oid":"5e49c42de3c23a1da881c1cb"},"name":"Berlin","incidents":{"$numberInt":"30"},"bad_incidents":"15","salary":{"$numberInt":"55000"}}
{"_id":{"$oid":"5e49c58ee3c23a1da881c1cc"},"name":"New York","good_incidents":{"$numberInt":"15"},"salary":{"$numberInt":"56500"}}
What I am trying to do is get these values:
The most repeated city in collection
The average of bad_incidents
The maximum value of good_incidents
Maximum salary where there are no bad_incidents
I am trying to wrap my head around how I can do this in one query, because I only need one value per field. I would be glad if somebody would lead me on the right track. No need for full solution
Regards!
You may perform MongoDB aggregation with $facet operator which allows compute several aggregation at once.
db.collection.aggregate([
{
$facet: {
repeated_city: [
{
$group: {
_id: "$name",
name: {
$first: "$name"
},
count: {
$sum: 1
}
}
},
{
$match: {
count: {
$gt: 1
}
}
},
{
$sort: {
count: -1
}
},
{
$limit: 1
}
],
bad_incidents: [
{
$group: {
_id: null,
avg_bad_incidents: {
$avg: {
$toInt: "$bad_incidents"
}
}
}
}
],
good_incidents: [
{
$group: {
_id: null,
max_good_incidents: {
$max: {
$toInt: "$good_incidents"
}
}
}
}
],
max_salary: [
{
$match: {
bad_incidents: {
$exists: false
}
}
},
{
$group: {
_id: null,
max_salary: {
$max: {
$toInt: "$salary"
}
}
}
}
]
}
},
{
$replaceWith: {
$mergeObjects: [
{
$arrayElemAt: [
"$repeated_city",
0
]
},
{
$arrayElemAt: [
"$bad_incidents",
0
]
},
{
$arrayElemAt: [
"$good_incidents",
0
]
},
{
$arrayElemAt: [
"$max_salary",
0
]
}
]
}
}
])
MongoPlayground
[
{
"_id": null,
"avg_bad_incidents": 34.666666666666664,
"count": 2,
"max_good_incidents": 50,
"max_salary": 56500,
"name": "New York"
}
]
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