count nested array inside documen using updateOne() function - node.js

const reset_qr_list_and_update_count = await stock_read_log.updateOne(
{
payload: {$ne:req.body.payload},
"qr_list.payload": req.body.new_qr_list[indexx].payload,
company_id:req.body.company_id
},
{
"$pull": {
"qr_list": {
payload: req.body.new_qr_list[indexx].payload
}
},
$set:{
qty: xx
},
}
);
$set:{
qty: model.aggreation({
//the query
}).count()
},
after pulling one of the list above,i want to re-count list left ,how can i achieve that within this function?

Related

aggregate with dynamic field path- mongo DB and nodeJS

I have a collection- 'products' that contains the following documents:
{
productName: "computer",
updateAt: "2022-07-12T12:44:47.485Z",
createAt: ""2022-06-12T10:34:03.485Z",
changeAt: ""2022-09-12T10:39:40.485Z"
}
I want to create an aggregation that convert the field "updateAt" from string to date.
for this, I created this aggregation:
db.products.aggregate([{
$set: {
updateAt: {
$dateFromString: {
dateString: '$updateAt'
}
}
},
},
{
$out: 'products'
}]
)
It works fine for this need, but as you can see I specified the field path "updateAt" in a hard coded way.I want to use the above aggregation in a dynamic way-
considering I have an array of fields that I want to change:
const fields = ['updateAt', 'createAt', 'changeAt']
I want to loop over the fields array and use each field as a fieldPath so I can transfer the field name to the aggregation, something like that-
fields.forEech(field -> {
db.products.aggregate([{
$set: {
`${field}`: {
$dateFromString: {
dateString: `$${field}`
}
}
},
},
{
$out: 'products'
}]
)
}
As you can understand it's not working for me....
How can I achieve my goal?
You have some errors in your nodejs function, also, aggregate method returns a Promise, so you will need to wait for it, to resolve before moving further.
Try this:
const fields = ['updateAt', 'createAt', 'changeAt']
for(let i=0; i < fields.length; i++) {
let field = fields[i];
await db.products.aggregate([{
"$set": {
[field]: {
"$dateFromString": {
"dateString": `$${field}`
}
}
},
},
{
"$out": 'products'
}]
)
}
Also, make the function containing this piece of code async.

deleting an object from array in mongo collection

I have a mongo schema like this.
{
userID:19202,
products:[ { id:020, name:'first' }]
}
I want to pop items from the product array based on id. I used the following command. although it didn't give any error, it also not deleting elements from an array.
userCart.updateOne(
{ userID:userID},
{ $pull: { products: { id:id } } }
)
.then((data) =>
{
if(data)
{
//data is {
"n": 1,
"nModified": 0,
"ok": 1
}
return res.json({
status:true,
message:"cart updated"
})
}
})
Demo - https://mongoplayground.net/p/mh6fXN21vyR
Make sure id and products.id are of the same type as in your document in the database. As your sample, both should be numbers.
if they both are number
db.collection.update({
userID: 19202
},
{
$pull: {
"products": { id: 20 }
}
})
Not Working here - https://mongoplayground.net/p/3zhv8yoH2o9 when "products": { id: "20" }. products.id is a string in the mongo query and in the database in number so mismatched.
Try this one:
db.userCart.update(
{ userID:userID },
{ $pull: { items: { id: 020 } } },
false, // Upsert
true, // Multi
);

check an array of string value with array of object in mongodb

I have array of strings like this
let fromHour = ['2.5','3','3.5']
let toHour = ['2.5','3','3.5']
I have an array of object saved in mongoDB
timeRange = [
{
from:'2.5',
to:'3'
},
{
from:'3',
to:'3.5'
}
]
I want to check if any of my array of string value exist in that object value
I have tried this but it give me this error ( Unrecognized expression '$match' )
checkAppoint = await Appointment.aggregate([
{
$project: {
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange: {
'$match': {
'from': { $in: fromHolder },
'to': { $in: toHolder },
},
},
},
},
]);
also I have tried this solution and it work for me but it take to much time so I am trying this with aggregate
checkAppoint = await Appointment.findOne({
date: myScheduleFinal[k].date,
status: { $in: ['pending', 'on-going'] },
timeRange:{$elemMatch:{
from:{$in:fromHolder},
to:{$in:toHolder}
}}
});
So anyone have a solution for that
Just try $elemMatch and $in operators,
using find() method
checkAppoint = await Appointment.find({
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
})
Playground
using aggregate() method
checkAppoint = await Appointment.aggregate([
{
$match: {
timeRange: {
$elemMatch: {
from: { $in: fromHour },
to: { $in: toHour }
}
}
}
}
])
Playground
So I have found a way around to solve this problem and I will share the solution I used
First I want to minimize my request to mongodb so I am now making just one request that bring all the appointment with the required date
and I want to make it this way because my fromHour and toHour array will change many time through single request
helperArray => contains all the day I want to check it's range
let checkAppoint = await Appointment.find({
date: { $in: helperArray },
status: { $in: ['pending', 'on-going'] },
});
now inside my for loop I will go through that data
checkAppoint.filter((singleAppoint) => {
if (singleAppoint._doc.date === myScheduleFinal[k].date) {
singleAppoint._doc.timeRange.map((singleTime) => {
if (fromHolder.includes(singleTime.from)) {
busy = true;
}
});
}
});

Mongodb update multiple documents with different values

I have been trying to use updatemany with mongoose. I want to update the values in database using an array of objects.
[
{
"variantId": "5e1760fbdfaf28038242d676",
"quantity": 5
},
{
"variantId": "5e17e67b73a34d53160c7252",
"quantity": 13
}
]
I want to use variantId as filter.
Model schema is:
let variantSchema = new mongoose.Schema({
variantName: String,
stocks: {
type: Number,
min: 0
},
regularPrice: {
type: Number,
required: true
},
salePrice: {
type: Number,
required: true
}
})
I want to filter the models using variantId and then decrease the stocks.
As you need to update multiple documents with multiple criteria then .updateMany() wouldn't work - it will work only if you need to update multiple documents with same value, Try this below query which will help you to get it done in one DB call :
const Mongoose = require("mongoose");
let variantSchema = new mongoose.Schema({
variantName: String,
stocks: {
type: Number,
min: 0
},
regularPrice: {
type: Number,
required: true
},
salePrice: {
type: Number,
required: true
}
})
const Variant = mongoose.model('variant', variantSchema, 'variant');
let input = [
{
"variantId": "5e1760fbdfaf28038242d676",
"quantity": 5
},
{
"variantId": "5e17e67b73a34d53160c7252",
"quantity": 13
}
]
let bulkArr = [];
for (const i of input) {
bulkArr.push({
updateOne: {
"filter": { "_id": Mongoose.Types.ObjectId(i.variantId) },
"update": { $inc: { "stocks": - i.quantity } }
}
})
}
Variant.bulkWrite(bulkArr)
Ref : MongoDB-bulkWrite
I don't think this can be done with a single Model.updateMany query. You will need to loop the array and use Model.update instead.
for (const { variantId, quantity } of objects) {
Model.update({ _id: variantId }, { $inc: { stocks: -quantity } });
}
To run this in a transaction (https://mongoosejs.com/docs/transactions.html), the code should look something like this (however I have not tried or tested this):
mongoose.startSession().then(async session => {
session.startTransaction();
for (const { variantId, quantity } of objects) {
await Model.update({ _id: variantId }, { $inc: { stocks: -quantity } }, { session });
}
await session.commitTransaction();
});

mongoDB find, update and pull in One Query

I want to do all the find the data from the collection and then want to update some field as well as depending on want to empty the array.
const addCityFilter = (req, res) => {
if (req.body.aCities === "") {
res.status(409).jsonp({ message: adminMessages.err_fill_val_properly });
return false;
} else {
var Cities = req.body.aCities.split(","); // It will make array of Cities
const filterType = { "geoGraphicalFilter.filterType": "cities", "geoGraphicalFilter.countries": [], "geoGraphicalFilter.aCoordinates": [] };
/** While using $addToset it ensure that to not add Duplicate Value
* $each will add all values in array
*/
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
}
},
{$set:{filterType}},
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});
}
};
Collection
geoGraphicalFilter: {
filterType: {
type:String,
enum: ["countries", "cities", "polygons"],
default: "countries"
},
countries: { type: Array },
cities: { type: Array },
aCoordinates: [
{
polygons: { type: Array }
}
]
}
But as result, the only city array is getting an update. No changes in filterType.
You appear to be passing the $set of filterType as the options argument, not the update argument.
huntingModel
.update(
{
_id: req.body.id,
},
{
$addToSet: {
"geoGraphicalFilter.cities": { $each: Cities }
},
$set: {
filterType
}
}
).then(function(data) {
res.status(200).jsonp({
message: adminMessages.succ_cityFilter_added
});
});

Resources