How to Update many elements in mongoose array which has embedded documents - node.js

I have this mongoose model
resourceId: {
type: String,
},
resourceName: {
type: String,
},
dateAndValue: [
{
date: { type: Date },
value: { type: Number },
},
],
project: {
type: mongoose.Schema.Types.ObjectId,
ref: 'project',
},
I want to update all value fileds of dateAndValue array elemets to "0" of a given resourceId, given project within a given date range!
await QuantumResourcesManpowerAdmin.updateMany(
{
project,
resourceId,
'dateAndValue.date': { $gte: startDate, $lte: endDate },
},
{
$set: {
'dateAndValue.$.value': 0,
},
},
{ upsert: true }
);
res.status(200).json({ success: true });
This is the code I used for it. It returns success but does not do any update.
All inputs are correct, something is wrong with only the updateMany query, all other functions work!

await QuantumResourcesManpowerAdmin.updateMany(
{
project,
resourceId,
'dateAndValue.date': { $gte: startDate, $lte: endDate },
},
{
$set: {
'dateAndValue.$[element].value': 0,
},
},
{arrayFilters:[{'element.date':{$gte: startDate, $lte: endDate }}] ,upsert: true }
);
res.status(200).json({ success: true });

Related

How can I query data between date range in array mongoose using express

I'm trying to query for multiple dates in date ranges in mongoose.
member: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Member",
},
point: {
type: Array,
},
recommended: [
{
member: {
type: mongoose.Schema.Types.ObjectId,
ref: "Member",
},
money: { type: Number },
date: {
type: Date,
default: new Date(),
},
},
],
matching: {
type: Array,
},
this is my model
{ const { date } = req.body;
let start = new Date(date[0]);
let end = new Date(date[1]); }
let result = await Income.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(req.params.id),
recommended: { $elemMatch: { $gt: start, $lt: end } },
},
},
{
$project: {
recommended: {
$filter: {
input: "$recommended",
as: "item",
cond: {
$and: [
{ $gt: ["$$item.date", start] },
{ $lt: ["$$item.date", end] },
],
},
},
},
},
},
]);
I send date from react antd date picker date: ["2022-06-20", "2022-06-25"]
this is controller
I don't understand why it's won't work what is the problem it's no error
api return empty array

Searching for all properties of a document using aggregation and project with change in date format in mongoose

My database model looks like
{
email: { type: String, required: true },
name: { type: String, required: true },
projectId: { type: String, required: true },
createdAt: { type: Date, required: false },
updatedAt: { type: Date, required: false },
};
createdAt is of format 2021-10-07T11:16:44.988Z and I wants at the time of fetching data from database date format should be 2022-02-25. so I wrote query to database like this:
const { id } = req.params;
const participantList = await ParticipantModel.aggregate([
{ $match: { projectId: id } },
{ $limit: limitInt },
{ $skip: skipInt },
{
$project: {
Date: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } },
},
},
]);
I got result as below:-
{ _id: 6218e52f43ec044180e69b84, Date: '2022-02-25' },
{ _id: 6218e5f543ec044180e69b97, Date: '2022-02-25' },
]
Expected result
[
{ _id: 6218e52f43ec044180e69b84,email:'xyz#gmail.com', name:'xyz',projectId:"01A", Date: '2022-02-25',updatedAt: 2022-02-25T14:18:23.708Z},
{ _id: 6218e5f543ec044180e69b97, email:'abc#gmail.com', name:'abc',projectId:"01B",Date: '2022-02-25' , updatedAt: 2022-02-25T14:21:41.313Z,},
]
How to solve this? Thank you for your help.
In $project guide of mongodb docs, set value to 1 each field if you want to show or 0 to hidden:
const { id } = req.params;
const participantList = await ParticipantModel.aggregate([
{$match:{projectId:id},},{$limit:limitInt},{$skip:skipInt},{$project:{
Date: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } },
email: 1, name: 1, projectId: 1, updatedAt: 1
}}

"$pull" doesn't delete the embedded documents of mongoose array

My mongo schema is as below:
resourceId: {
type: String,
},
resourceName: {
type: String,
},
dateAndValue: [
{
date: { type: Date },
value: { type: Number },
},
],
Once data is added to the "dateAndValue" array, I want to remove all objects in the array that includes '0' as the value. This is the code I used for it but it doesn't seem to work:
await QuantumResourcesManpowerAdmin.updateMany(
{ resourceId: qrmaRecord.resourceId },
{
$pull: {
dateAndValue: {
$elemMatch: { value: 0 },
},
},
},
{ multi: true }
);
Found the answer, $elemMatch should be removed from the above code. So,
await QuantumResourcesManpowerAdmin.update(
{ resourceId: qrmaRecord.resourceId },
{
$pull: {
dateAndValue: {
value: 0,
},
},
},
{ safe: true, multi: true }
);
would work without any issue

Mongoose aggreagate with group not working

In my Node.JS API, it is possible to order and get menus. The structure of an ordered menu looks like the following (the main schema is the orderMenuSchema; menuItemSchema is for the subdocument-array with ordered items):
var menuItemSchema = mongoose.Schema({
itemId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
prepared: {
type: Boolean,
default: false
},
finished: {
type: Boolean,
default: false
},
timestamp: {
type: Date,
default: Date()
}
}, {_id: false})
var orderMenuSchema = mongoose.Schema({
orderId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
menuId: {
type: mongoose.Schema.Types.ObjectId,
required: true
},
items: {
type: [menuItemSchema],
required: true,
validate: menuItemsCheck
},
finished: {
type: Boolean,
default: false
},
timestamp: {
type: Date,
default: Date()
}
})
Example Data:
{
"_id":"5d2333a1841a0e4ef05873d0",
"finished":false,
"timestamp":"2019-07-08T12:14:04.000Z",
"menuId":"5d189ffdbe02ef0b00b22370",
"items":[
{
"prepared":false,
"finished":false,
"timestamp":"2019-07-08T12:14:04.000Z",
"itemId":"5d189ffdbe02ef0b00b2236d"
},
{
"prepared":false,
"finished":false,
"timestamp":"2019-07-08T12:14:04.000Z",
"itemId":"5d189ffdbe02ef0b00b2236e"
},
{
"prepared":false,
"finished":false,
"timestamp":"2019-07-08T12:14:04.000Z",
"itemId":"5d189ffdbe02ef0b00b2236f"
}
],
"orderId":"5d2333a1841a0e4ef05873c3",
"__v":0
}
Whether an item is prepared or not is stored in the prepared field of the menuItem.
Each menu has multiple items to choose from, and the user is able to have only some items - that's why the orderMenuSchema has an array of subdocuments called "items" in which only the ordered items are stored.
Now I would like to get all unprepared menus, group them by the menuID
and then group them by the itemID - everything with a Mongoose
aggregation.
So, I think I need two groupings: The first one by the menuId, the second one by the itemId.
Furthermore, I would like to know how many of each item are unprepared - so after grouping by the menuId, I need to get a count of all unprepared items
Expected Output:
I thought of something like this:
{
"result":[
{
"menuID":"tastefulMenu123",
"items":[
{
"itemId":"noodlesoop123",
"unpreparedCount":13
},
{
"itemId":"tastyBurger123",
"unpreparedCount":2
},
{
"itemId":"icecoldIce123",
"unpreparedCount":20
}
]
}
]
}
There will be an array of subdocuments, one subdocument for each menuId. Each subdocument than has an array of items in which the itemID as well as the unpreparedCount are stored.
What I already tried (not working):
OrderMenu.aggregate([
{$unwind: "$items"},
{ $project: { prepared: 1, itemId: 1} },
{ $match: {
prepared: false,
timestamp: {
$gte: today,
$lt: tomorrow
}
}},
{ $group: {
_id: {menuId: '$menuId', itemId: '$itemId'},
count: { $sum: 1 }
}}
]).then(result => {
console.log(result)
return Promise.resolve(result)
}).catch(error => {
console.log(error)
return Promise.reject(500)
})
Any help would be appreciated!

Mongoose unique value per day

Im trying to configure mongoose schema unique param. I need to allow write to DB no more than one unique author per one day period.
Schema.index( { author: 1, created: 1 } , { unique: true} ) not works, here I can't enter time period.
What better way to decide this case?
const Report = new Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'DiscordUserList',
required: true
},
reports: [{ reportNum: { type: Number }, text: { type: String }, date: { type: Date, default: Date.now } }],
questionsDone: [{ questionNum: { type: Number }, done: { type: Boolean }, date: { type: Date, default: Date.now } }],
created: {
type: Date,
default: Date.now
}
}, { strict: false })
Report.plugin(mongoosePaginate)
const reportListSchema = mongoose.model('ReportList', Report)
module.exports = reportListSchema
You could do an update operation with $setOnInsert and upsert option i.e if the update() with upsert: true had found a matching document, then MongoDB performs an update, applying the $set operation but ignoring the $setOnInsert operation. Thus your typical update would be as follows:
import moment from 'moment'
const start = moment().startOf('day').toDate() // set to 12:00 am today
const end = moment().endOf('day').toDate() // set to 23:59 pm today
ReportList.findOneAndUpdate(
{
'author': author_id,
'created': { '$gte': start, '$lte': end }
},
{
'$set': { 'author': author_id },
'$setOnInsert': { 'created': moment().toDate() }
},
{ 'upsert': true, 'new': true },
(err, report) => {
console.log(report)
}
)
or using the setDefaultsOnInsert option which when this and upsert are true, mongoose will apply the defaults specified in the model's schema if a new document is created:
ReportList.findOneAndUpdate(
{
'author': author_id,
'created': { '$gte': start, '$lte': end }
},
{ '$set': { 'author': author_id } },
{
'upsert': true,
'new': true,
'setDefaultsOnInsert': true
},
(err, report) => {
console.log(report)
}
)

Resources