check and update nested documents in mongoose mongodb - node.js

i am new in mongodb and mongoose and i don't know how i can change an object in array which is in other object .
here is simple version of my schema
const shiftSchema = new Schema({
phone: String,
order: {
startTime: String,
finishTime: String,
orders: [{
stat: boolean,
orderId: Number
}]
}
});
orderId is actually the time every 5 so first object in orders has startTime+5 value as orderId and the last one has finishTime value.
so now i want to find the doc that has for example 0911111 as phone , 04090405 as startTime , 04090900 as finishTime , and inside it i want to update just the object that it's orderId is 04090435 if it's stat was false and also update 2 objects before it . which are 04090430 and 04090425 and also check their stat to be false and if even one of these 3 objects has true stat do not update it and send error.
i know it has answered many times but i can't find any solution for mine in specific conditions ,so please help me.
Note: i know that for updating this kind of arrays i can do something like this :
Shift.updateOne({
'order.orders': {$elemMatch: {orderId: {$lte: start}, stat: "true"}}
}, {
'$set': {'order.orders.$.stat': 'ready'}
})
but it just update whole Shift Collection but i only just want to update one doc.
All tips will be appreciated. Thank You

Related

Specific aggregated query using mongoose / mongodb

I need help to achieve the following task.
I want to query all documents from a mongodb using mongoose of type TokenBalance. The schema looks like this
const Schema = mongoose.Schema(
{
address : { type: String, index: true },
ethervalue: {type: Number, required:true},
balances : []
},
{ timestamps: true }
);
The balances [] Array inside that schema holds multiple objects of this structure
{address: addresshash, symbol: someSymbol, balance: somebalance, usdvalue: usdvalueOfBalance}
What I need, is to query all Docs of Type TokenBalance within a timespan that is given and then from all of these documents sum the usdvalues grouped by symbols.
For example the output I need should look like this:
[
{symbol: BTC, balance: 100.000},
{symbol: ETC, balance: 120.000}
...
]
I'm having difficulties writing the correct aggregation for this. Especially I don't know how to group by the documents "balances" array and its symbols and sum the values.
I hope my question is clear and someone could help me.
Thank you in advance

MongoDB update query in subarray

An update in the array of objects inside another array of objects.
mongodb field that I'm working on:
otherFields: values,
tasks: [
{
_id: mongodb.objectID(),
title: string,
items:[{
_id: mongodb.objectID(),
title: string,
completed: boolean //field need to be update.
}]
},
{}...
],
otherFields: value
sample mongodb document
I need to find the document using the task_id and the item_id and update a completed field in item of a task. Using the mongoose findOneAndUpdate method
const path = "tasks.$.items." + item_id + "completed";
collectionName.findOneAndUpdate(
{ _id: req.user._id, "tasks._id": taskID },
{ $set: { [path]: true }});
The above query doesn't work!!!
There is no need to use multiple query conditions, since you'd like to update a specific item that has an unique ID. Therefore you could use something along the lines:
collectionName.findOneAndUpdate(
{ 'tasks.items._id': itemID },
...
);
Keep in mind this structure is far away from optimized as it would basically look through the entire database...
Also now that I think of it, you'd also have issue with the update, as there are two nested arrays within the document. Read more here: How to Update Multiple Array Elements in mongodb

How to find an object inside an array inside a mongoose model?

I'm trying to query an object that's inside an item which is inside a mongoose model, when I'm trying to find that object with the find() method or _.find() method, I can't get access to the object for some reason and when I console.log() it, it gives me undefined or when I use array.filter() it gives me an empty array, which means the object that I'm trying to access does not meet the criteria that I give it in the lodash find method, but then when I look at my database I see that the object does actually have the properties to meet the criteria. So I don't know what I'm doing wrong, here's my code: as you can see I'm trying to get the information of the item that the user clicked on and want to see:
router.get("/:category/:itemId", (req, res) => {
console.log(req.params.itemId);
//gives the item id that the user clicked on
console.log(req.params.category);
//gives the name of category so I can find items inside it
Category.findOne({ name: req.params.category }, (err, category) => {
const items = category.items; //the array of items
console.log(items); //gives an array back
const item = _.find(items, { _id: req.params.itemId });
console.log(item); //gives the value of 'undefined' for whatever reason
});
});
The category Schema:
const catSchema = new mongoose.Schema({
name: {
type: String,
default: "Unlisted",
},
items: [
{
name: String,
price: Number,
description: String,
img: String,
dateAdded: Date,
lastUpdated: Date,
},
],
dateCreated: Date,
lastUpdate: Date,
});
well the answer is a little bit obvious, you are using MongoDB and in Mongo you have "_ID" you can use that "_ID" only with Mongoose! so you just have to remove the underscore and that is it! do it like this const item = _.find(items, { id: req.params.itemId });
hope you are doing better.
When I look at your Schema I see that the item field is an array of objects which doesn't have an _id inside so when you create a new instance of catShema it just generates an _id field for the new instance but not for each item inside the items array, just also enter the id of the item in question because according to my understanding, you must also have a model called items in your database
When you save these records in your database, you will generate an element with this structure
{
_id: String, // auto generated
name: String,
items: [ {"name1", "price1", "description1", "imgUrl1", "dateAdded1", "lastUpdated1"},{"name2", "price2", "description2", "imgUrl2", "dateAdded1", "lastUpdated2"}, ...],
dateCreated: Date,
lastUpdate: Date
}
Note : the code provided at the top is only an illustration of the object which will be registered in the database and not a valid code
Here you can notice that there is not a field called _id in the object sent inside the database.
My suggestion to solve this issue is
To create an additional field inside the items array called _id like :
{
...,
items: [
{
_id: {
type: String,
unique : true,
required: true // to make sure you will always have it when you create a new instance
},
...
... // the rest of fields of items
},
...
Now when you create a new instance make sure in the object you enter in the database the _id is recorded when you call the catInstance.save() so inside the catInstance object you have to add the current Id of the element to be able to filter using this field.
Hope my answer helped, if you have any additional questions, please let me know
Happy coding ...

mongoose model refuses to update array of objects inside array of objects

I've a schema for a store inventory. The location has locationcategories array in the schema and inside that array, I have items[] array.
My issue is updating this items[] inside the locationcategories[]. I use the mongodb shell to update that array (using updateOne()) and it works (update my items[] inside locationcategories[]) but when I do it using mongoose model ("Locations") it doesn't update, in my console, it just shows { n: 1, nModified: 0, ok: 1 } which indicate that everything was found but didn't modify anything. When I check the db, it doesn't have any new items added.
Here is code I use in mongoshell which updates items[] inside locationcategories[]
db.locations.updateOne({"locationname" :"My Town", "locationcategories":{"$elemMatch":{"categoryname": "Media"}}},{$push:{"locationcategories.$.items": {"test":"test"}}})
In my application server route (expressjs) I enter the following:
Location.updateOne(
{ "locationname": "My Town", "locationcategories": {"$elemMatch":{"categoryname": "Media"}}},
{$push: {"locationcategories.$.items": {"test":"test"}}},
{new : true, upsert: true },
function (error, results) {
console.log("findByIdAndUpdate results :", results);
}
);
my mongooose schema-model:
var Schema = mongoose.Schema;
var locationSchema = new Schema({
locationname: String,
locationdescription: String,
locationcategories: [{ categoryorder: Number, categoryname: String,
categorydescription: String, items[{itemname: String }]}],
items: [{categoryid : String, itemorder: Number, itemname: String, itemdescription: String, itemprice: Number }],
created_at: Date
});
var Location = mongoose.model('Location', locationSchema);
export default Location;
I'm using mognodb version 4.02
Model.updateOne should work but it is not adding anything to my db. I read many of the stackoverflow.com issues but I couldn't find anything that indicate an issue except this old question from years ago which he had an issue updating array inside array. I find it hard to believe that there is an issue and no one addressed it after all those years but I might be wrong.
If the mongo shell execute and add to db correctly, it leads me to believe that the mongoose model or schema are responsible for the issue or my updateOne() code is wrong.
Any idea why?
Got it. So I changed items inside the locationcategories[] to categoryItems[] and it works.
The .$ operator looks for the first array with the name items which was items outside but I was posting the data to the model's first array.
Make sure you name the arrays in your model with unique names and point the $push to the correct array.
Also upgrded mongodb from version 4.0 to the latest one 4.41.

updating a data object in nested array in mongodb by mongoose

i have a serious problem in updating my data . i have no idea how i can update a specific field in an object of an array in my document .
here is my Schema model :
var shiftSchema = new Schema({
Phone: String,
final: Boolean,
statusSH: String,
order: {
startTime: String,
finishTime: String,
income: String,
orders: [{
stat: String,
orderId: String,
customerPhone: String,
orderQuantity: String,
orderCost: String,
orderCondition: String,
orderTag: String
}]
}
});
when i use "find" it gives me the document and not just the object.
now how can i edit "stat" by finding "orderId" ?
Note that i do not have the index of the object that i want to update and i can just use "find"or "findOne".
i search all over the web and i couldn't find a good guide and example .
sorry for my bad english.
All tips will be appreciated. Thank You.
You can try to run this query, to update the stat property:
shiftSchema.updateOne({
'order.orders.orderId': 'id'
}, {
'$set': {'order.orders.$.stat': 'newStatus'}
})
.then((result) => {
console.log(result)
}, (e) => {
console.log(e)
})
You can see I used positional $ operator to access an element in the array and update it without specifying the position of the element (with index).
I also used $set to replace the value of a field.
With just find or findOne you will not make the actual update.

Resources