I am not able to save & update a Mongoose subdocument's array element using the set function.
Brief
I use a front end HTML form that creates a request eventually calling this controller in my Node Express REST API. The req.body parameter being passed into the controller is an object matching the structure of an element of the purchaseOrders array. I successfully GET the element, modify it in a pretty form on the front end, then POST to an app level controller which then creates a PUT request into my API controller (API controller function below).
Problem
I can't seem to use the set method on an element of the array I'm targetting. Secondly, if I use a direct assignment instead, I get a save error.
When I use
customer[0].purchaseOrders[0] = req.body
I receive a type error
TypeError: purchaseOrderRaw.save is not a function
and if I use the set method
customer[0].purchaseOrders[0].set(req.body)
I receive a different type error
TypeError: purchaseOrderRaw[0].purchaseOrders[0].set is not a function
Please note, my goal is not to assign each field individually. Ideally, I would like to use the set method so that I can pass the req.body directly into the array. What am I doing wrong?
Here is the Document returned by Mongoose using the aggregate framework. I'm basically trying to update the first element in the purchaseOrders array.
{
"customerID":1,
"purchaseOrders":[
{
"_id":"5eee249ac534edf5d09ed036",
"purchaseOrderID":450012321
}
]
}
The controller in my REST API. I've removed a lot of error handling for brevity.
const Customer = mongoose.model('Customer');
const purchaseOrderUpdate = (req, res) => {
Customer
.aggregate()
.match({customerID:req.params.customerID})
.project({_id:0, customerID:1, purchaseOrders: {
$filter: {
input: '$purchaseOrders',
as: 'purchaseOrders',
cond: { $eq: ['$$purchaseOrders.purchaseOrderID', req.params.purchaseOrderID]}
}}})
.exec((err, customer) => {
customer[0].purchaseOrders[0].set(req.body);
customer.save(); // excluded the callback for brevity
});
}
Related
I want to retrieve data from api and assign it to some value inside the angular component. In subscribe I'm trying to assign the data to loggedUser and then call function inside this subscribe to navigate to another component with this received object. Unfortunately I got the error : The requested path contains undefined segment at index 1. I want to have this object set outside the subscribe too. How can I achieve this?
logIn() {
this.portfolioAppService.logIn(this.loggingUser).subscribe((data) => {
this.loggedUser = data;
console.log(this.loggedUser);
console.log(data);
this.navigateToProfile(this.loggedUser.Id);
});
}
navigateToProfile(id: number) {
this.router.navigate(['/profile', id]);
}
console output
You are using an incorrectly named property when calling navigateToProfile.
From your console output, I can see that the data object in the subscribe looks like this:
{
id: 35,
// ..
}
But you are calling the function like this:
this.navigateToProfile(this.loggedUser.Id);
Instead, use the property id (lower case)
this.navigateToProfile(this.loggedUser.id);
To narrow this problem down in the future, try being more specific in your testing. Humans are good at seeing what they want to see and will assume the problem is more complicated than it is. If you had tried console.log(this.loggedUser.Id), you would have seen the result undefined, and worked out the problem yourself.
I'm trying to add another property to existing object returning from findOne() promise in mongoose.
In the response I get the object without the property convertName
app.get('/getItem', (req, res) => {
var itemID = req.query.itemID;
Item.findOne({_id: itemID}).then(item => {
item.convertName = 'cm';
res.send(item);
}).catch( err => {
res.status(401).send();
});
})
I know that the way to add another property to an existing object is similar to this, just specify the property name and set a value to it, so I don't know why it is not working in this case.
Hope you can explain and help me why its not working.
It's a bit complicated with Mongoose: by default MongooseDocument is returned by query, and the property that you try to add to such a document is not reflected on its serialized value (the one that is sent in the response).
One possible way around this is using lean() method to enable lean option. Quoting the doc:
Documents returned from queries with the lean option enabled are plain
javascript objects, not MongooseDocuments. They have no save method,
getters/setters or other Mongoose magic applied.
I have something like the following code:
User.findOne(id)
.exec((err, user) => {
Pets.find(_.pluck(user.pets, 'id'))
.populate("toys")
.exec((err, petsWithToys) => {
user.pets = petsWithToys;
return res.ok({ user: user });
});
});
When I look at the response in the client I don't see the toys array inside the pet.
I thought maybe this was due to overriding the toJSON function in my User model but even when removing it I get the same behavior.
Also, I've found out that if I assign the values to a new property that is not defined in the model, I do see the values at the client. I.e. if I do
user.petsNew = petsWithToys;
I will see the fully populated property.
I've seen the documentation of toObject where is says it removes instance methods (here) but I am not sure why the collection is considered a method and don't understand how after changing the value it is still removed.
Any comments/explanations/workarounds?
P.S. Tried to step through the code but can't step into toObject...
Add user = user.toJSON(); before user.pets = petsWithToys;
Check https://stackoverflow.com/a/43500017/1435132
I am trying to fetch a series of objects from my Node.js-based, MongoDB instance using Restangular; however, I am not able to guarantee the number of objects I wish to grab by ID will always be the same.
To demonstrate, here is a code snippet of the principle:
Restangular
.several('users',
userList[0], userList[1], userList[2], userList[3], userList[4],
userList[5], userList[6], userList[7], userList[8], userList[9])
.get().then(function (users) { //...
userList is an array of IDs passed in as a part of a method:
requestUsersById = function (userList) { //...
The problem is that I cannot guarantee the size of the array. Is there a way to pass an array of IDs using Restangular? Or, am I just stuck making separate requests for each?
The ideal result would be something like:
Restangular
.several('users', userList)
.get().then(function (users) { //...
The Restangular API doesn't seem to natively support this, but I believe you can accomplish what you're trying to do by making using the apply() method.
In this case, you'd append the name of the collection users to the head of your userList array. Try this out:
// Store the userList in a new array to preserve the initial list
// (not sure if you use it somewhere else
var usersQuery = userList;
// Shift the collection name to be the first parameter in the array
usersQuery.unshift("users");
// Perform the Restangular call
Restangular
.several.apply(null,usersQuery)
.get().then(function (users) { //...
I'm using meteor and meteor.angular.
I have a list of documents which are published by meteor with a restricted number of fields, since I don't need the full objects just for the list.
Meteor.publish("trackers", function () {
return Trackers.find({},
{fields:
{
'projectTracker.projectSPID':1,
'projectTracker.projectName':1,
'projectTracker.date':1
}
});
});
Then, clicking through on one of the list items, I use the object's _id to subscribe to a second Meteor.publish that I hoped would return the full object.
Meteor.publish("trackerBy_id", function (id) {
return Trackers.find({
'_id': id
});
});
But, the _id is already with the client data, there is no update and I just get the limited object I was using for the original list rather than the single full object.
Using url params does cause the full object to be published.
Meteor.publish("trackerBy_params", function (SPID,date) {
return Trackers.find({
'projectTracker.projectSPID': SPID,
'projectTracker.date': date
});
});
How can I use _id when a limited dataset already exists and trigger Meteor to publish the full object?