TypeORM select data from nested relations - sql

Using
await this.budgetRepository.createQueryBuilder("budget")
.leftJoinAndSelect("budget.contact", "contact")
.leftJoinAndSelect("contact.photo", "contactPhoto")
.getMany();
I get a list with objects like this:
Budget {
id: 1,
unnecessary_property1: something,
contact: Contact {
unnecessary_property2: something,
photo: Photo {
unnecessary_property3: something,
url: "url.com"
},
},
}
But I want to select only the necessary properties in the nested objects (relations) and get a list of objects like this:
Budget {
id: 1,
contact: Contact {
photo: Photo {
url: "url.com"
},
},
}
How is that possible with TypeORM?

This is possible but we have to select everything manually with .select()
await this.budgetRepository.createQueryBuilder("budget")
.leftJoinAndSelect("budget.contact", "contact")
.leftJoinAndSelect("contact.photo", "contactPhoto")
.select(['budget.id', 'contactPhoto.url']
.getMany();

If you're using repository pattern that you will be achieve the similar result with:
await this.budgetRepository.find({
relations: ["contact", "contact.photo"]
})

You would have to use the .select() function and pass the given properties you want for each entity.
for your example:
const user = await createQueryBuilder("budget")
.leftJoinAndSelect("budget.contact", "contact")
.leftJoinAndSelect("contact.photo", "contactPhoto")
.select([/* everything from budget */, 'contact.photo.url'....]) // added selection
.getMany();

Related

what is the proper way to get my google account profile image (URL) in NodeJS

see below error message and source code, doesn't work even after I added person fields of photos:
TypeError: Cannot read properties of undefined (reading 'url')
var p = google.people("v1");
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,photos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
res.json({
name: encoder.htmlEncode(user.displayName),
picture: user.image.url,
});
}
);
You should have a look into the docs. The people.get request returns a Person object. And such a Person does not have an image property, so you cant't access user.image.url because user.image does not exist. Neither does user.displayName, btw.
What a Person actually looks like is as follows (the ... meaning there are additional properties too, look up in the docs, if you need more)
{
...
coverPhotos: [{url: "https://url.to/image", ...}],
...
names: [{ displayName: "John Doe", ...}],
...
}
So to get the name and picture, first of all, instead of photos you need to request coverPhotos. Then you can extract the desired values, as follow:
p.people.get(
{
resourceName: "people/me",
personFields: "names,emailAddresses,coverPhotos",
auth: oauth2Client,
},
function (err, user) {
if (err) { return; }
let
name = user.names?.[0]?.displayName || "John Doe",
url = user.coverPhotos?.[0]?.url
res.json({
name: encoder.htmlEncode(name),
picture: user.image.url,
});
});
I used the conditional chaining ?. here, to make sure, this code does not run into an exception if for instance coverPhotos does not exist or is an empty array.

Why is my SQL data returning undefined in my array methods?

The First array returned when I console log person
The second array that returns when I console log person
I am trying to create a function that pulls the data from 2 tables in my SQL database. I am using async/await, which is still new to me. The issue is somewhere in the two array methods; for some reason they are returning data as undefined.
async function updateRole() {
console.log('hi');
//cycle through both arrays and create new arrays with same information using maps
//return object with employee and role info
const allEmployees = await db.promise().query(`SELECT * FROM employees`);
const allRoles = await db.promise().query(`SELECT * FROM roles`);
console.log(allEmployees);
const employeeChoices = allEmployees.map((person) => {
return {
name: `${person.first_name} ${person.last_name}`,
value: person.id
}
})
const roleChoices = allRoles.map((role) => {
return {
name: role.title,
value: role.id
}
})
const { employeeId, roleId } = await inquirer.prompt([
{
type: 'list',
name: 'employeeId',
message: 'Which employee would you like to update?',
choices: employeeChoices
},
{
type: 'list',
name: 'roleId',
message: 'What is their new role?',
choices: roleChoices
}])
await db.promise().query(`UPDATE employees SET role_id = ? WHERE id = ?`, [roleId, employeeId])
console.log('Successfully updated employee!');
askQuestions();
Update: I added screenshots fo the console log for person. role returns the same format, but obviously different data. I am unsure what the array of ColumnDefinition objects does, or why it's there.

Where should I use computed and methods in Vue js? (need proper guideline)

Look at the image below and please explain where should I use computed instead of methods and vice versa? It confuses me.
As a rule of thumb: a computed is a simple getter (though they can be setters, but that's not something you'd typically use) that is dependent on one or more properties. It'll update automatically when those properties change. You cannot pass it parameters. You would use a method when you need to pass a parameter and/or need to perform an action or mutation.
data() {
firstName: 'Bert',
lastName: 'Ernie'
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
This will return "Bert Ernie" and will update automatically when either firstName or lastName change.
Now if you need to change something, or for example select something from a list using a parameter, you would use a method.
data() {
users: [
{ id: 1, name: 'Bert' }.
{ id: 2, name: 'Ernie' }
]
},
methods: {
getUser(userid) {
return this.users.find(user => user.id === userid);
},
setUserName(userid, newName) {
const user = this.users.find(user => user.id === userid);
if (user) {
user.name = newName;
}
}
}

How to compare results of two vuejs computed properties

Our application has events that users can apply to, as well as blog posts written about different events. We want to show users all of the blog posts for events where they have applied.
Each post has an eventId and each application object contains event.id. We want to show all of the posts where the the eventId is equal to one of the application.event.id's.
Here are our computed properties...
computed: {
...mapState(['posts', 'currentUser', 'applications']),
myApplications: function() {
return this.applications.filter((application) => {
return application.user.id === this.currentUser.uid
})
},
myEventPosts: function() {
return this.posts.filter((post => {
post.eventId.includes(this.myApplications.event.id)
})
}
How can we change meEventPosts to get the show the correct results?
Thanks!
This question is mostly related to JS, not Vue and calculated properties. It will be better if you create such a code snippet the next time, as I did below.
const posts = [{eventId: 1, name: 'Post 1'}, {eventId: 2, name: 'Post 2'}, {eventId: 3, name: 'Post 3'}];
const myApplications = [{eventId: 2, name: 'App 2'}];
const myEventPosts = function () {
const eventsIds = myApplications.map((app) => app.eventId);
return posts.filter((post) => eventsIds.includes(post.eventId));
}
console.log('posts:', myEventPosts());
So your myEventPosts computed property should look like:
myEventPosts: function() {
const eventsIds = this.myApplications.map((app) => app.eventId);
return this.posts.filter((post) => eventsIds.includes(post.eventId));
}

GraphQL, Dataloader, [ORM or not], hasMany relationship understanding

I'm using for the first time Facebook's dataloader (https://github.com/facebook/dataloader).
What I don't understand is how to use it when I have 1 to many relationships.
Here it is a reproduction of my problem: https://enshrined-hydrant.glitch.me.
If you use this query in the Playground:
query {
persons {
name
bestFriend {
name
}
opponents {
name
}
}
}
you get values.
But if you open the console log here: https://glitch.com/edit/#!/enshrined-hydrant you can see these database calls I want to avoid:
My Person type is:
type Person {
id: ID!
name: String!
bestFriend: Person
opponents: [Person]
}
I can use dataloader good for bestFriend: Person but I don't understand how to use it with opponents: [Person].
As you can see the resolver has to return an array of values.
Have you any hint about this?
You need to create batched endpoints to work with dataloader - it can't do batching by itself.
For example, you probably want the following endpoints:
GET /persons - returns all people
POST /bestFriends, Array<personId>` - returns an array of best friends matchin the corresponding array of `personId`s
Then, your dataloaders can look like:
function batchedBestFriends(personIds) {
return fetch('/bestFriends', {
method: 'POST',
body: JSON.stringify(personIds))
}).then(response => response.json());
// We assume above that the API returns a straight array of the data.
// If the data was keyed, you could add another accessor such as
// .then(data => data.bestFriends)
}
// The `keys` here will just be the accumulated list of `personId`s from the `load` call in the resolver
const bestFriendLoader = new DataLoader(keys => batchedBestFriends(keys));
Now, your resolver will look something like:
const PersonType = new GraphQLObjectType({
...
bestFriend: {
type: BestFriendType,
resolve: (person, args, context) => {
return bestFriendLoader.load(person.id);
}
}
});