How to join column, that when i launch my function, he return me only columns name instead of entity_columnName.
I'm using TypeORM, and i try this;
const data = this.conn.getRepository(User).createQueryBuilder('user');
data.leftJoinAndSelect('user.orders', 'orders');
data.getRawMany();
but return me:
firstName: ...
lastName: ...
age: ...
order_name: ...
order_price: ...
instead of:
firstName: ...
lastName: ...
age: ...
name: ...
price: ...
can someone tell me how do this? thanks for any help
How are your User and Order entities defined?
If you define a relation (e.g. OneToMany) with the eager: true option, then TypeORM will automatically include the related entities when you query using the repository *find methods. It won't do this when you use the QueryBuilder, where you have to add them such as with leftJoinAndSelect() (as you have done).
An example from an Invoice entity that has OneToMany line items:
#OneToMany(
() => InvoiceLineItem,
(item: InvoiceLineItem) => item.invoice,
{ eager: true }
)
items: InvoiceLineItem[]
Per the example, if I were then to find() or findMany() invoices, then the related objects, items will be included as well because eager: true.
This behaviour might translate well to your situation with users and orders.
Also be aware of the differences between getMany() and getRawMany() when using the query builder.
If you use getMany() then TypeORM will automagically give you entities back (e.g. you'd get an instance of User with property orders that is an array of Order instances). The property names will be correct.
Since you added the NestJS tag to your question, also understand serialization:
https://docs.nestjs.com/techniques/serialization
There is a built-in ClassSerializerInterceptor that comes with NestJS that you might find useful.
In your controller you can decorate the class or any of its methods e.g.
#UseInterceptors(ClassSerializerInterceptor)
This will transform the response to JSON, and will apply the rules specified with class-transformer decorators on the entity/DTO class.
If you were to use this interceptor, the response sent to the client will have your desired property names.
If you really want to modify the response that your client gets back, you can also look into writing your own Interceptor.
Related
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.
I'm having trouble understanding how to retrieve information from a GraphQL Union. I have something in place like this:
const Profile = StudentProfile | TeacherProfile
Then in my resolver I have:
Profile: {
__resolveType(obj, context, info) {
if (obj.studentId) {
return 'StudentProfile'
} else if (obj.salaryGrade) {
return 'TeacherProfile'
}
},
},
This doesn't throw any errors, but when I run a query like this:
query {
listUsers {
id
firstName
lastName
email
password
profile {
__typename
... on StudentProfile {
studentId
}
... on TeacherProfile {
salaryGrade
}
}
}
}
This returns everything except for profile which just returns null. I'm using Sequelize to handle my database work, but my understanding of Unions was that it would simply look up the relevant type for the ID being queried and return the appropriate details in the query.
If I'm mistaken, how can I get this query to work?
edit:
My list user resolver:
const listUsers = async (root, { filter }, { models }) => {
const Op = Sequelize.Op
return models.User.findAll(
filter
? {
where: {
[Op.or]: [
{
email: filter,
},
{
firstName: filter,
},
{
lastName: filter,
},
],
},
}
: {},
)
}
User model relations (very simple and has no relation to profiles):
User.associate = function(models) {
User.belongsTo(models.UserType)
User.belongsTo(models.UserRole)
}
and my generic user resolvers:
User: {
async type(type) {
return type.getUserType()
},
async role(role) {
return role.getUserRole()
},
},
The easiest way to go about this is to utilize a single table (i.e. single table inheritance).
Create a table that includes columns for all the types. For example, it would include both student_id and salary_grade columns, even though these will be exposed as fields on separate types in your schema.
Add a "type" column that identifies each row's actual type. In practice, it's helpful to name this column __typename (more on that later).
Create a Sequelize model for your table. Again, this model will include all attributes, even if they don't apply to a specific type.
Define your GraphQL types and your interface/union type. You can provide a __resolveType method that returns the appropriate type name based on the "type" field you added. However, if you named this field __typename and populated it with the names of the GraphQL types you are exposing, you can actually skip this step!
You can use your model like normal, utilizing find methods to query your table or creating associations with it. For example, you might add a relationship like User.belongsTo(Profile) and then lazy load it: User.findAll({ include: [Profile] }).
The biggest drawback to this approach is you lose database- and model-level validation. Maybe salary_grade should never be null for a TeacherProfile but you cannot enforce this with a constraint or set the allowNull property for the attribute to false. At best, you can only rely on GraphQL's type system to enforce validation but this is not ideal.
You can take this a step further and create additional Sequelize models for each individual "type". These models would still point to the same table, but would only include attributes specific to the fields you're exposing for each type. This way, you could at least enforce "required" attributes at the model level. Then, for example, you use your Profile model for querying all profiles, but use the TeacherProfile when inserting or updating a teacher profile. This works pretty well, just be mindful that you cannot use the sync method when structuring your models like this -- you'll need to handle migrations manually. You shouldn't use sync in production anyway, so it's not a huge deal, but definitely something to be mindful of.
I have been building my Meteor React application but ran into a problem now. I would like to delete all the "fake" generated data I added. But it's not working.
I have tried several things, from server side deleting (via the console) and via a method. But none of these have worked so far.
So my question: How can you delete all data in a collection that matches a query like this one:
comments.remove({ adminSpark : { $regex: 'false', $options: 'i' }});
--> Not sure if this method is correct.
I am using SimpleSchema + ValidatedMethod.
The complete method looks like this at the moment:
export const emptyDatabase = new ValidatedMethod({
name: 'AllComments.remove',
validate: new SimpleSchema({
event: { type: Boolean }
}).validator(),
run({ event }) {
comments.remove({ adminSpark : { $regex: 'false', $options: 'i' }});
},
});
So what I want to do is delete all the comments in the collection that match adminSpark: false.
The validity of your selector depends on wether your code is trusted or not. Untrusted code can only remove elements using their _id as a selector. If you are not sure wether your code is trusted or not, I'd suggest :
Collection.find({/*query here*/}).map(function(doc){
Collection.remove(doc._id);
})
Also this should be performed in a space were you are both subscribed to the elements you want to remove and where you have permissions to do so.
Documentation:
Trusted code can use an arbitrary Mongo selector to find the documents to remove, and can remove more than one document at once by passing a selector that matches multiple documents. It bypasses any access control rules set up by allow and deny. The number of removed documents will be returned from remove if you don’t pass a callback.
As a safety measure, if selector is omitted (or is undefined), no documents will be removed. Set selector to {} if you really want to remove all documents from your collection.
Untrusted code can only remove a single document at a time, specified by its _id. The document is removed only after checking any applicable allow and deny rules. The number of removed documents will be returned to the callback.
On the server you should be able to simply do:
comments.remove({ adminSpark : 'false' });
If all your false values are lower case - this is an exact match.
Pray tell, why would one store false as a string instead of a boolean?
So i have a complex date model coming from the server to feed my Angular2 component. Following shows a small part of the template for this component:
<div>
<span>{{Person.Address.City}}</span>
<input type="text" [(ngModel)]="Person.Address.City" />
</div>
The Address might be null or undefined depending on the data that's returned from the server. I know that elvis operator will save me from one error:
<span>{{Person?.Address?.City}}</span>
but unfortuantely it won't save me for [(ngModel)]="Person.Address.City" as there is no elvis defined for that. You'll get a parser error if you do something like [(ngModel)]="Person?.Address?.City" and if you don't then you'll get the null exception.
Here are two simplest variation of data, although there can be a lot more:
{
Name:'sam',
LastName: 'jones',
Address: {
Street: '123 somewhere',
City: 'some land'
State: 'SL'
}
}
or...
{
Name:'sam',
LastName: 'jones'
}
Since the responsibility of handling these scenarios should be on Angular2 rather than the server that provides the data, due to separation of presentation and business logic, how would I handle the scenario(s)?
So as it turns out, you either maintain 3 models, one for front-end (Angular2), one for middle tier (ASP.NET, JAVA, etc...) and another for your data model. Or you could make sure, as i did, that your middle-tier model will not have a null complex object. This means initializing complex properties inside your model and getting away with 2 models.
Also to note, if you have don't or can't modify your middle-tier model, then your only option is to create a compatible model for your front-end (Angular2) and merge as necessary once data has returned from API, service, etc..
At the service level you can add a blank object for Address. Right after receiving a response.
This way you fix the problem at it's source for entire application.
Here is simple solution with RxJS:
this._http.get(url)
.map(res => res.json())
.map(res => {
if (res.Address === null || res.Address === undefined) {
res.Address = {}
}
return object;
});
You might also want to consider removing the Address object if it is blank, right before saving it.
I got nested JSON data from the server like this:
{
name: "Alice",
profile: {
something: "abc"
}
}
and I have the following model:
App.User = Ember.Object.extend({
name: null,
profile: Ember.Object.extend({
something: null
})
})
If I simply do App.User.create(attrs) or user.setProperties(attrs), the profile object gets overwritten by plain JS object, so currently I'm doing this:
var profileAttr = attrs.profile;
delete attrs.profile
user.setProperties(attrs); // or user = App.User.create(attrs);
user.get('profile').setProperties(profileAttrs);
It works, but I've got it in a few places and in the real code I've got more than one nested object, so I was wondering if it's ok to override User#create and User#setProperties methods to do it automatically. Maybe there's some better way?
Based on your comment, you want the automatic merging behaviour you get with models (the sort of thing you get with .extend()). In that case, you could try registering a custom transformer, something like:
App.ObjectTransform = DS.Transform.extend({
deserialize: function(json){
return Ember.Object.create(json);
}
});
App.User = DS.Model.extend({
profile: DS.attr('object')
});
See: https://github.com/emberjs/data/blob/master/TRANSITION.md#json-transforms
If you are doing your server requests without an adapter you can use the model class method load() with either an array of json objects or a single object. This will refresh any known records already cached and stash away the JSON for future primary key based lookups. You can also call load() on a model instance with a JSON hash as well but it will only update that single model instance.
Its unclear why you are not using an adapter, you can extend one of the Ember Model adapters and override the the record loading there, eg. extend from the RESTAdapter and do any required transform on the JSON if required by overriding _loadRecordFromData
You can also override your models load function to transform data received if required as well. The Ember Model source is fairly easy to read so its not hard to extend to your requirements.