Stripped Attributes with toJSON/toObject - javascript

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

Related

Pass a variable into a query (Firebase)

this is really frustrating me I hope you kind people can assist me.
I have a firebase firestore db that stores info about properties and cities. All properties contain a key:value pair called location_city. It is a string that stores the City that the property resides in.
I have made a dropdown box on a webpage with a list of available cities. The idea is to dynamically display properties from the selected city, by means of the .where() method. The third parameter accepted by the method is the string you want to query against.
I want to pass the text value of the dropdown list into the query.
Here's my code:
let selectedCityViewHomes;
function getDropdownSelection(sel) {
selectedCityViewHomes = sel.options[sel.selectedIndex].text;
selectedCityViewHomes.toString();
}
db.collection('Homes')
.where('location_city', '==', selectedCityViewHomes)
.get()
.then(snapshot => {
snapshot.docs.forEach(doc => {
renderHome(doc);
});
});
The query method only seems to work if you manually enter a string into the parameter and does not seem to allow you to pass a variable (which is a string) into the method.
I have tried concatenating "'" either side to mimic 'Manchester', for example and this did not work either.
TIA
Charlie
EDIT: I found where i had gone wrong, it was an issue of scope i think. I fixed it by creating a function which wrapped the db.collection code and passed in the variable as an argument.
const updateHomesViewHomes = (input) => {
db.collection('Homes').where('location_city', '==', input).get().then((snapshot) => {
homesViewHomes.innerHTML = "";
snapshot.docs.forEach(doc => {
renderHome(doc);
});
});
};
Thanks for the replies, hope this helps someone.

How to get and set a ref for a newly cached related object in Apollo client InMemoryCache?

I have a set of related items like so:
book {
id
...
related_entity {
id
...
}
}
which apollo caches as two separate cache objects, where the related_entity field on book is a ref to an EntityNode object. This is fine, the related entity data is also used elsewhere outside of the context of a book so having it separate works, and everything seems well and good and updates as expected...except in the case where the related entity does not exist on the initial fetch (and thus the ref on the book object is null) and I create one later on.
I've tried adding an update function to the useMutation hook that creates the aforementioned related_entity per their documentation: https://www.apollographql.com/docs/react/caching/cache-interaction/#example-adding-an-item-to-a-list like this:
const [mutateEntity, _i] = useMutation(CREATE_OR_UPDATE_ENTITY,{
update(cache, {data}) {
cache.modify({
id: `BookNode:${bookId}`,
fields: {
relatedEntity(_i) {
const newEntityRef = cache.writeFragment({
fragment: gql`
fragment NewEntity on EntityNode {
id
...someOtherAttr
}`,
data: data.entityData
});
return newEntityRef;
}
}
})
}
});
but no matter what I seem to try, newEntityRef is always undefined, even though the new EntityNode is definitely in the cache and can be read just fine using the exact same fragment. I could give up and just force a refetch of the Book object, but the data is already right there.
Am I doing something wrong/is there a better way?
Barring that is there another way to get a ref for a cached object given you have its identifier?
It looks like this is actually an issue with apollo-cache-persist - I removed it and the code above functions as expected per the docs. It also looks like I could instead update to the new version under a different package name apollo3-cache-persist, but I ended up not needing cache persistence anyway.

Mongoose save() not saving changes

I have a fully functioning CRUD app that I'm building some additional functionality for. The new functionality allows users to make changes to a list of vendors. They can add new vendors, update them and delete them. The add and delete seem to be working just fine, but updating doesn't seem to be working even though it follows a similar method I use in the existing CRUD functionality elsewhere in the app. Here's my code:
// async function from AXIOS request
const { original, updatedVendor } = req.body;
let list = await Vendor.findOne({ id: 1 });
if (!list) return res.status(500).json({ msg: 'Vendors not found' });
let indexOfUpdate = list.vendors.findIndex(
(element) => element.id === original.id
);
list.vendors[indexOfUpdate].id = updatedVendor.id;
list.vendors[indexOfUpdate].name = updatedVendor.name;
const updated = await list.save();
res.json(updated);
The save() isn't updating the existing document on the DB side. I've console logged that the list.vendors array of objects is, indeed, being changed, but save() isn't doing the saving.
EDIT:
A note on the manner of using save, this format doesn't work either:
list.save().then(res.json(list));
EDIT 2:
To answer the questions about seeing the logs, I cannot post the full console.log(list.vendors) as it contains private information, however, I can confirm that the change made to the list is showing up when I run the following in the VendorSchema:
VendorSchema.post('save', function () {
console.log(util.inspect(this, { maxArrayLength: null }));
});
However, the save still isn't changing the DB side.
Since you are using nested objects, Mongoose will not be able to detect the changes made. You need to mark the modified as an object before the save
list.markModified('vendors');

How to customize response object in Bookshelf JS?

I want to add a custom property to the standard Bookshelf.js response object. In this case, the goal is to fetchAll() Regions and append the property link to each Region. The value of link is simply /some/api/route/${region.id}.
I believe there are two ways to achieve this: (1) modify to the Regions model to include some function getRegionLink() to generate the desired value; or (2) iterate over and modify the response object. I think that (1) is preferred, but I can imagine when (2) may be necessary.
With that context, I haven't been able to figure out how to do (2). The Bookshelf.js docs state that _.each() is available, though the lodash docs deprecated each in favor of forEach. However, the following did not work as expected. Some error occurs. On a related note, the err objects log empty on Postman.
Region Service
Region.forge()
.fetchAll()
.then(regions => {
_.forEach(regions, region => {
region.link = `${API_BASE}/location/regions/v1/${region.id}`;
});
res.json(regions);
.catch(err => {
res.status(404).json(err);
});
The core of this question is answered by the "virtuals" plugin for Bookshelf. Related post: Bookshelf.js set attribute not in database

adding a new property to existing doesn't work

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.

Categories