I am trying to get an array of objects with a certain ID from my database inside a route of my server, and then add change a property of an object inside the array (instead of returning an objectID to my client I want to return the Document as an object with the specific ID).
This is my code:
let orders = await Order.find({restaurant: restaurantID, status: 'PROCESSING'})
for(let order of orders){ //iterate through all orders
for(let element of order.dishes){ //iterate through order.dishes array (called 'element' since the array contains objects)
let dish = await Dish.findOne({_id: element._id})
element['dish'] = dish //create new property for the dish object
delete element._id //remove the ID property since it already exists inside the element.dish object
}
}
Every order
object inside orders
contains an array called dishes
, which contains objects with the properties amount
and an id
. Since my frontend can't do much with the ID, I want to delete the id property and add a new property called dish, which contains the dish object the id points to.
The problem I am facing is that I don't know how to manipulate the orders
arrays content. Whenever I parse orders
to JSON and sent it inside my response, I recieve a JSON array of order objects just like I want to. But when I add the code I pasted above, it does not change anything inside my orders.
Whenever I log the element inside my for loops it looks like this: EmbeddedDocument {__parentArray: Proxy, __index: 0, $__parent: model, $__: InternalCache, $isNew: false, …}
but when I parse it to JSON I recieve exactely what I want, namely this: {"amount":1,"_id":"6183b84fec1c3e109a2271be"}
Is orders
even an array in this case? If not, what would be the easiest way to manipulate it/get the documents as an array?
This is what orders looks like when I watch it in my debug window:
price (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
price (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
restaurant (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
restaurant (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
status (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
status (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
timestamp (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
timestamp (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
user (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
user (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
__v (get):ƒ () {\n return this[getSymbol].call(this.$__[scopeSymbol] || this, path);\n }
__v (set):ƒ (v) {\n this.$set.call(this.$__[scopeSymbol] || this, path, v);\n }
__proto__:Model
length:1
And in postman, the res.body looks like this (almost exactely like it should but instead of the dishes object it contains only the id):
[
{
"_id": "6183b84fec1c3e109a2271bd",
"user": "6166bc426181646198fc483c",
"restaurant": "6176947ce8b10986b018930e",
"dishes": [
{
"amount": 1,
"_id": "6183b84fec1c3e109a2271be"
},
{
"amount": 2,
"_id": "6183b84fec1c3e109a2271bf"
}
],
"price": 30,
"status": "PROCESSING",
"timestamp": "2021-11-04T10:39:11.800Z",
"__v": 0
}
]
If this was already solved, please send me a link to the question/answer. I spent the last few hours trying to solve this and I already looked at a lot of questions but none of the answers were helpful for me
It is a common question. People are often disconcerted because they can't alter the data coming from MongoDB.
The thing is, Mongoose is kind of weird; it does not return simple JSON, but constructs and returns a collection of Mongoose objects. These objects have extra methods, like .save()
, but above all their nested objects are immutable . Simply changing their properties have no effect.
In order to modify the data returned by Mongoose, you have two possibilities :
.markModified()
It's a really weird concept, but the changes you make won't be applied until you mark them as modified. For instance :
element['dish'] = dish;
order.save();
This will have no effect. The name will remain unchanged in Mongo. You need .markModified()
:
element['dish'] = dish;
order.markModified("dishes");
order.save(); // Works now :|
You can prevent Mongoose from constructing its own objects by using .lean()
. this will return simple JSON data that can be tampered with at will.
let orders = await Order
.find({restaurant: restaurantID, status: 'PROCESSING'})
.lean()
.exec(); // Also add .exec(), it returns a true Promise and not a thenable
Bonus : lean()
is faster and lighter.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.